2

我正在使用 Monitor 类来管理关键部分。但有时我会遇到SynchronizationLockException以下消息

An unhandled exception of type 'System.Threading.SynchronizationLockException' occurred in ManagedType.dll
Additional information: Object synchronization method was called from an unsynchronized block of code.

我的代码如下

Object^ lockObj = gcnew Object(); //Global variable
bool GetValue()
{
    try
    {
        Monitor::Enter(lockObj);
        return this.value;
    }
    finally
    {
        Monitor::Exit(lockObj);
    }
}

调用SynchronizationLockException时抛出。Monitor::Exit(lockObj)

我在这个论坛和互联网上搜索过,但大多数主题包括 MSDN 都说“当您尝试在 Monitor.Enter() 和 Monitor.Exit() 中使用值类型变量而不是引用类型时,将引发此异常”。

但就我而言,我使用 lockObj 作为参考对象。所以我不知道为什么它会抛出这个异常。有人可以帮助我吗?

非常感谢,

T&T集团!

4

3 回答 3

5

发布的代码根本上是错误的。Monitor::Enter() 调用必须出现在 try{} 块之外。

故障模式令人讨厌且无法诊断。如果 Enter() 调用因任何原因引发异常,则 finally{} 块中的 Exit() 调用将因记录的异常而崩溃,因为从未进入监视器。这是无法诊断的,因为该异常替换了 Enter() 方法抛出的异常,您无法看到它也无法捕获原始异常。所以你不知道为什么这段代码失败并且无法解决问题。

将 Enter 调用移到 try 块上方。这仍然不能解决您的代码崩溃的问题,但至少您现在可以获得一些关于真正出错的信息。

顺便说一句,请注意 .NET 4.0 中添加的 Monitor::Enter() 重载,旨在解决此类问题。它需要一个额外的 bool% 参数,当 Enter() 成功时将设置为 true,因此您知道调用 Exit() 是安全的。

于 2013-06-14T15:19:33.650 回答
4

@Hans 部分正确。使用采用 ref bool 的 Monitor.Enter 重载。这个重载总是设置传递给 ref 参数 lockTaken 的变量的值,即使方法抛出异常,所以变量的值是测试是否必须释放锁的可靠方法。但请务必将 Monitor.Enter 调用保留在 try 块内。您的代码应该类似于

bool acquiredLock = false;

try
{
    Monitor.Enter(lockObject, ref acquiredLock);

    // Code that accesses resources that are protected by the lock.

}
finally
{
    if (acquiredLock)
    {
        Monitor.Exit(lockObject);
    }
}
于 2013-06-14T15:37:22.297 回答
-1

好的,我刚刚处理了这个。我相信这会解决你的问题。尝试将对象设置为NULL;它对我有用。

Object^ lockObj=NULL;

Monitor::Enter(lockObj);
try
{
     return this.value;
}
 finally
 {
     Monitor::Exit(lockObj);
 }
于 2015-04-17T20:18:39.893 回答