所以我有一个类,有一些方法都使用锁定,以防止有人使用我的类的实例和多个线程访问它时发生奇怪的事情:
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。
答案 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)
锁定禁止您尝试做的事情 - 这就是它的目的。
要做的一件事是创建一个可以从methodA
和methodB
访问的私有方法。该方法不会使用锁定,也不会是线程安全的,但可以从任何一种锁定方法中调用。
答案 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)
您的锁机制需要允许以递归方式(仅通过相同的线程)进行锁定,通常称为reentrant
。 lock
(内部Monitor课程)。
同一个线程在没有阻塞的情况下多次调用Enter是合法的;但是,在等待对象的其他线程将解除阻塞之前,必须调用相同数量的Exit调用。
另见Recursive / nested locking in C# with the lock statement 和Re-entrant locks in C#
正如Henk Holterman在评论中指出的那样,Monitor
类已经是可重入的。 lock
语句管理对基础Enter
类的Exit
和Monitor
次调用。
ReaderWriterLockSlim
类是锁定机制的示例,可以在reentrant
和non-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,它也不会被阻塞,因为锁已经在线程中。 代码如下。
调用“MethodA” - &gt;获取锁定 - &gt;调用“MethodB”(不会因为线程已被获取锁定而被阻止)并且执行将完成。
在之前从另一个线程执行之间调用“MethodB”,执行将被锁定,因为lock是第一个线程。