有关使用Monitor.TryEnter和锁定对象的问题

Cap*_*mic 13 .net c# multithreading locking

请考虑以下函数,该函数仅实现对一个线程的非阻塞访问.

public bool TryCancelGroup()
{
    if (Monitor.TryEnter(_locked))
    {
        if (_locked == false)
        {
            _locked = true;

            try
            {
                // do something
            }
            catch (Exception ex)
            {
                _locked = false;
            }
            finally
            {
                Monitor.Exit(_locked);
            }
        }
        return _locked;
    }
    else
    {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是_locked变量的定义方式.

bool _locked = false;
Run Code Online (Sandbox Code Playgroud)

现在,当程序到达时,Monitor.Exit(_locked);它会抛出一个System.Threading.SynchronizationLockException说明_locked变量之前未同步的说法.

当_locked变量被定义为对象之前,这一切都在起作用

object _locked = new object();
Run Code Online (Sandbox Code Playgroud)

当我将它更改为bool以便将其用作布尔标志时,我开始得到此异常.

Jar*_*Par 27

原因是Monitor方法都采用System.Object参数.当你传入bool一个盒子需要转换为Object.框操作System.Object为每个调用生成一个新值.因此,TryEnterExit方法看到不同的对象并导致异常.

_locked被输入到Object没有必要为一个盒子.因此,TryEnterExit方法看到相同的对象,并且可以正常运行.

关于代码的一些其他评论

  • 在所有情况下,TryEnter必须与Exit配对,为了理智,Exit调用应该在finally块中.否则你正在邀请一个死锁场景
  • _locked变量仅false在异常情况下设置.如果执行没有产生异常,它将保持为真,并且没有线程将再次进入该if块.

  • @Captain,当包含`bool`的任何类型的值类型用于键入`System.Object`的位置或接口时将发生装箱操作. (3认同)

小智 5

将监视器上的超时设置为0有助于实现所需的行为.使用全局声明的对象来锁定.

static object mylock = new object();
Run Code Online (Sandbox Code Playgroud)

....

if (Monitor.TryEnter(mylock, 0))
{
    try
    {
           // Do work
    }
    finally
    {
        Monitor.Exit(mylock);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 就我在反射器中看到的而言,Monitor.TryEnter(mylock,0)与Monitor.TryEnter(mylock)相同. (2认同)