使用Monitor.Enter和Monitor.Exit时,我似乎遇到了并发问题。有时我的代码会挂在以下Monitor.Exit语句中:
public void EndInit()
{
Monitor.Enter(this.lockObj);
this.initCount--;
if (this.initCount == 0) {
this.IsInitializing = false;
this.IsInitialized = true;
this.OnInitialized();
}
// sometimes, this Exit will never return ...
Monitor.Exit(this.lockObj);
}
只有一个地方,我的 lockObj 使用了:
public void BeginInit()
{
Monitor.Enter(this.lockObj);
this.initCount++;
this.IsInitializing = true;
this.IsInitialized = false;
Monitor.Exit(this.lockObj);
}
这就是我声明这个同步对象的方式:
private readonly object lockObj = new object();
我正在撕掉我的头发,发现它在这里发生了什么,但没有成功。我希望Monitor.Enter()
能够阻止,直到我的同步对象被释放,但为什么Monitor.Exit()
会被阻止?我无法在 MSDN 中找到有关此行为的任何解释。
注意我无法重现这种行为,它相当随机地发生(好吧,我知道“随机”不是正确的措辞)。
非常感谢任何想法或有用的提示!
和Thorsten
答案 0 :(得分:3)
我从之前的评论中回答。因为当try finally
中发生异常时,您应该使用Monitor.Exit
构造正确地调用OnInitialize()
。
因此代码将成为
public void EndInit()
{
Monitor.Enter(this.lockObj);
try
{
this.initCount--;
if (this.initCount == 0) {
this.IsInitializing = false;
this.IsInitialized = true;
this.OnInitialized();
}
}
finally
{
Monitor.Exit(this.lockObj);
}
}
第二种方法也是如此。
它也可以这样编写
public void EndInit()
{
lock(this.lockObj)
{
this.initCount--;
if (this.initCount == 0) {
this.IsInitializing = false;
this.IsInitialized = true;
this.OnInitialized();
}
}
}
修改强>
可以找到Joe Albahari撰写的关于线程的非常好的解释here。这是当之无愧的阅读。
编辑2(完整性)
如Damien_The_Unbeliever所述,还有overload。
这只适用于.NET 4及更高版本。使用监视器的代码将变为:
public void EndInit()
{
bool lockAcuired = false;
try
{
Monitor.Enter(this.lockObj, ref lockAquired);
this.initCount--;
if (this.initCount == 0) {
this.IsInitializing = false;
this.IsInitialized = true;
this.OnInitialized();
}
}
finally
{
if(lockAquired)
Monitor.Exit(this.lockObj);
}
}