首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Monitor.TryEnter / Monitor.Exit和SynchronizationLockException

Monitor.TryEnter / Monitor.Exit和SynchronizationLockException
EN

Stack Overflow用户
提问于 2012-12-30 17:22:04
回答 3查看 8.6K关注 0票数 5

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

代码语言:javascript
运行
复制
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来同步进入和退出,但我不确定它是否足够“安全”。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-12-31 18:11:36

既然你认为把Monitor.Exit的调用放在try-catch中是“硬的”(脏?),这里有一个非常简单的想法,试着“把硬的去掉”。锁对于同一线程是可重入的,如果一个线程在释放之前成功获取,则来自另一个线程的尝试将失败。这样你就可以考虑像这样的事情:

代码语言:javascript
运行
复制
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两次,因为我们锁定了它两次,一次在代码外部,另一次就在这里。

票数 2
EN

Stack Overflow用户

发布于 2012-12-30 17:39:44

所以问题是,我如何知道做Monitor.Exit的线程和做Monitor.Enter的线程是不是同一个线程?

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

然而,这只是一个编码问题--你应该修改你的代码,这样它甚至不会在不应该释放监视器的时候尝试释放它。

代码语言:javascript
运行
复制
if (!Monitor.TryEnter(obj, 2000))
{
    throw new Exception(...);
}
try
{
    // Presumably other code
}
finally
{
     Monitor.Exit(obj);
}

或者更好的是,如果您使用的是.NET 4,则使用接受ret参数的overload of TryEnter

代码语言:javascript
运行
复制
bool gotMonitor = false;
try
{
    Monitor.TryEnter(obj, ref gotMonitor);
    if (!gotMonitor)
    {
        throw new Exception(...);
    }
    // Presumably other code
}
finally
{
    if (gotMonitor)
    {
        Monitor.Exit(obj);
    }
}
票数 18
EN

Stack Overflow用户

发布于 2018-01-19 19:44:59

我知道这是一个古老的问题,但不管怎样,这是我的答案。我会将try-finally结构移到if中:

代码语言:javascript
运行
复制
try
{
    if(Monitor.TryEnter(obj, 2000))
    {
        try
        {
            // code here
        }
        finally
        {
            Monitor.Exit(obj);
        }
    }
    else
    {
        throw new Exception("Can't acquire lock");
    }
}
catch
{
    // log
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14089640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档