所以我有一个类,其中有一些方法,这些方法都使用锁定,以防止当有人使用我的类的实例并有多个线程访问它时发生奇怪的事情:
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()
执行操作时使用它(这就是我使用储物柜对象的原因)。
当然,我不希望
MethodA()
在 MethodB()
做事时做事。我基本上只想同时使用所有方法中的一种,但是 MethodA()
需要以某种方式访问 MethodB()
而无需删除锁(以便它始终保持完全线程安全)。
我真的希望我想问的问题是可以理解的...如果对我的问题有任何疑问,请继续在下面发布。也非常感谢答案/解决方案!
解决方案可能非常简单,只是我没有看到它。
顺便说一句,上面应该是 C# 代码。
一个简单的解决方案是创建一个 private 方法,其中包含
MethodB
所做的事情,可以由 MethodA
和另一个 public 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();
}
}
}
附注
我认为对于您和其他人来说,为什么您的代码在某种程度上“设计”是为了造成死锁,这是显而易见的。
: 显然
lock(object) {}
是
重入,正如评论中指出的那样,所以明显的僵局甚至不是一个。
这里要做的一件事是创建一个私有方法,您可以从
methodA
和
methodB
访问该方法。该方法不会使用锁定,并且不是线程安全的,但可以从任一锁定方法调用。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.
reentrant
。
lock
(内部Monitor类)。 同一个线程多次调用 Enter 且不阻塞是合法的;但是,在等待该对象的其他线程解除阻塞之前,必须调用相同数量的 Exit 调用。
C# 中使用 lock 语句的递归/嵌套锁定另请参阅
和 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();
}
```
因为根据微软的说法,一旦获得调用,即使程序在同一个流程中调用锁,也不会被阻塞,因为锁已经在线程中了。 该代码的工作原理如下。