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

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

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()当前已锁定了locker对象,因此无法使用。

我想公开访问MethodB() ,因此您可以在需要时手动调用它,但我不希望在MethodA()使用它(这就是我使用锁定器对象的原因)。

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

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

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

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

一个简单的解决方案是创建一个私有方法,该方法包含MethodBMethodA以及另一个公共 MethodB可以调用的MethodB

私有 MethodB不会锁定,只有公共方法会锁定。

例如:

 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(); } } } 

PS

我认为对于您和其他所有人来说,为什么您的代码在某种程度上旨在创建死锁是显而易见的。


更新

显然, lock(object) {}是可重入的,如注释中所指出的,因此明显的死锁甚至不是一个。

锁定禁止你正在尝试做什么 – 这就是它的目的。

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

你有竞争条件:它使数据不正确。 我想方法A写一个字符串类型的静态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. 

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

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

另请参见C#中的递归/嵌套锁定,其中包含锁定语句和C#中的 重入锁定

正如Henk Holterman在评论中所指出的, Monitor类已经是可重入的。 lock语句正在管理对底层Monitor类的正确的EnterExit调用。

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

var rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

用你的lock { ... }替换lock { ... }

 ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); ... try { rwLock.EnterWriteLock(); // Does something } finally { rwLock.ExitWriteLock(); } 

“`

您编写的代码是正确的。

因为根据微软的说法,即使程序在同一个流程中要求锁定,一旦获得调用,它就不会被锁定,因为锁定已经在线程中。 代码如下。

  1. 调用“MethodA” – >获取锁定 – >调用“MethodB”(不会因为线程已被获取而被阻止锁定)并执行完毕。

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