6

是否可以检测同一线程是否试图释放锁?我们在代码中有很多地方看起来像:

try
{
    try
    {
       if(!Monitor.TryEnter(obj, 2000)) 
       { 
            throw new Exception("can not lock"); 
       }
    }
    finally
    {
       Monitor.Exit(obj);
    }
}
catch
{
    //Log
}

上面的代码非常简化,实际上Enter和Exit语句位于自定义对象(锁管理器)中。

问题是,在那个结构中,我们SynchronizationLockException在尝试“退出”时遇到了问题,因为它看起来像没有成功锁定的线程,最终试图释放。

所以问题是,我如何知道制作 Monitor.Exit 的线程是否与制作 Monitor.Enter 的线程相同?
我认为我可以使用 CurrentThread.Id 来同步进入和退出,但我不确定它是否足够“安全”。

4

3 回答 3

19

所以问题是,我如何知道制作 Monitor.Exit 的线程是否与制作 Monitor.Enter 的线程相同?

据我所知,你不能轻易做到。您无法找出哪个线程拥有监视器。

然而,这只是一个编码问题——你应该改变你的代码,这样它就不会在不应该释放监视器的时候尝试释放它。所以你上面的代码可以重写为:

if (!Monitor.TryEnter(obj, 2000))
{
    throw new Exception(...);
}
try
{
    // Presumably other code
}
finally
{
     Monitor.Exit(obj);
}

或者更好的是,如果您使用的是 .NET 4,请使用接受参数的重载:TryEnterret

bool gotMonitor = false;
try
{
    Monitor.TryEnter(obj, ref gotMonitor);
    if (!gotMonitor)
    {
        throw new Exception(...);
    }
    // Presumably other code
}
finally
{
    if (gotMonitor)
    {
        Monitor.Exit(obj);
    }
}
于 2012-12-30T09:39:43.783 回答
2

正如您认为在 try-catch 中调用 Monitor.Exit 是 'durty'(脏?),这里有一个非常简单的想法,试图“带走 durty”。锁对于同一个线程是可重入的,如果一个线程成功获取,在它释放之前,另一个线程的尝试将失败。这样您就可以考虑以下内容:

public void Exit(object key) {
    if(!IsActive) {
        return;
    }

    if(LockDictionary.ContainsKey(key)) {
        var syncObject=LockDictionary[key];

        if(Monitor.TryEnter(syncObject.SyncObject, 0)) {
            SetLockExit(syncObject);
            Monitor.Exit(syncObject.SyncObject);
            Monitor.Exit(syncObject.SyncObject);
        }
    }
}

我们调用 Monitor.Exit 两次,因为我们将它锁定了两次,一次在代码外部,一次在此处。

于 2012-12-31T10:11:35.717 回答
1

我知道这是一个较老的问题,但无论如何这是我的答案。我会在 if 中移动 try-finally 构造:

try
{
    if(Monitor.TryEnter(obj, 2000))
    {
        try
        {
            // code here
        }
        finally
        {
            Monitor.Exit(obj);
        }
    }
    else
    {
        throw new Exception("Can't acquire lock");
    }
}
catch
{
    // log
}
于 2018-01-19T11:44:59.213 回答