多线程和锁定(线程安全操作)

时间:2015-07-04 15:01:56

标签: c# multithreading thread-safety locking

所以我有一个类,有一些方法都使用锁定,以防止有人使用我的类的实例和多个线程访问它时发生奇怪的事情:

public class SomeRandomClass
{
    private object locker = new object();

    public void MethodA()
    {
        lock (locker)
        {
            // Does something
            MethodB();
        }
    }

    public void MethodB()
    {
        lock (locker)
        {
            // Does something else
        }
    }
}

我们可以看到,MethodB()会自动访问MethodA(),但由于MethodA()当前已锁定了锁定对象,因此无法正常工作。

我想公开访问MethodB(),因此您可以在需要时手动调用它,但我不希望在MethodA()做事时使用它(这就是为什么我和#39; m使用储物柜对象。)

当然,MethodA()正在做事情时,我不希望MethodB()做某事。我基本上只希望同时使用所有方法中的一个,但MethodA()需要以某种方式访问​​MethodB()而不删除锁(以便它始终保持完全线程安全)。

我真的希望我能提出的问题是可以理解的......如果对我的问题有任何疑问,请继续将其发布在下方。答案/解决方案也非常受欢迎!

解决方案可能非常简单,我只是没有看到它。

顺便说一下,上面应该是C#-code。

5 个答案:

答案 0 :(得分:2)

一个简单的解决方案是创建一个私有方法,其中包含MethodB可以调用的MethodA和另一个公共 { {1}}

私有 MethodB不会锁定,只会公开。

例如:

MethodB

P.S。

我认为您和其他所有人都明白为什么您的代码有点设计来创建死锁。

<强>更新

显然public class SomeRandomClass { private object locker = new object(); public void MethodA { lock(locker) { // exclusive club // do something before calling _methodB _methodB(); } } private void _methodB { // do that, what used to be done by MethodB } public void MethodB { //this one only exists to expose _methodB in a thread-safe context lock(locker) { _methodB(); } } } re-entrant,正如评论中所指出的那样,所以明显的僵局甚至不是一个。

答案 1 :(得分:0)

锁定禁止您尝试做的事情 - 这就是它的目的。

要做的一件事是创建一个可以从methodAmethodB访问的私有方法。该方法不会使用锁定,也不会是线程安全的,但可以从任何一种锁定方法中调用。

答案 2 :(得分:0)

这里有竞争条件:它使数据不正确。我想方法是写一个string类型的静态theVar变量:

thread A -> call method A -> lock -> change theVar to "A"
thread B -> call method B -> wait because thread A keep lock
thread A -> release lock to call method B
    The bug here: thread B process theVar of "A"
    If method B only read theVar, it's Ok.

答案 3 :(得分:0)

您的锁机制需要允许以递归方式(仅通过相同的线程)进行锁定,通常称为reentrantlock(内部Monitor课程)。

  

同一个线程在没有阻塞的情况下多次调用Enter是合法的;但是,在等待对象的其他线程将解除阻塞之前,必须调用相同数量的Exit调用。

另见Recursive / nested locking in C# with the lock statementRe-entrant locks in C#

正如Henk Holterman在评论中指出的那样,Monitor类已经是可重入的。 lock语句管理对基础Enter类的ExitMonitor次调用。

ReaderWriterLockSlim类是锁定机制的示例,可以在reentrantnon-reentrant之间进行选择。见https://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim(v=vs.110).aspx

var rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

将您的lock { ... }替换为

ReaderWriterLockSlim rwLock = 
    new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

...

try 
{
    rwLock.EnterWriteLock();
    // Does something
}    
finally 
{
    rwLock.ExitWriteLock();
}

```

答案 4 :(得分:0)

您编写的准则是正确的。

因为根据Microsoft的说法,一旦获得调用,即使程序在同一个流程中调用了lock,它也不会被阻塞,因为锁已经在线程中。 代码如下。

  1. 调用“MethodA” - &gt;获取锁定 - &gt;调用“MethodB”(不会因为线程已被获取锁定而被阻止)并且执行将完成。

  2. 在之前从另一个线程执行之间调用“MethodB”,执行将被锁定,因为lock是第一个线程。