Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 关于使用Monitor.TryCenter和锁定对象的问题_C#_.net_Multithreading_Locking - Fatal编程技术网

C# 关于使用Monitor.TryCenter和锁定对象的问题

C# 关于使用Monitor.TryCenter和锁定对象的问题,c#,.net,multithreading,locking,C#,.net,Multithreading,Locking,考虑以下只对一个线程实现非阻塞访问的函数 public bool TryCancelGroup() { if (Monitor.TryEnter(_locked)) { if (_locked == false) { _locked = true; try { // do something }

考虑以下只对一个线程实现非阻塞访问的函数

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;
    }
}
下面是如何定义
\u-locked
变量

bool _locked = false;
现在当程序到达
Monitor.Exit(_锁定)时
它抛出一个
System.Threading.SynchronizationLockException
,表示之前未同步锁定的变量

当_locked变量被定义为object时,这一切都在运行

object _locked = new object();

当我将其更改为bool以便将其用作布尔标志时,我开始出现此异常。

原因是
监视器
方法都采用
系统对象
参数。当您传入
bool
时,需要一个框来转换为
对象
。box操作为每个调用生成一个新的
System.Object
值。因此,
TryEnter
Exit
方法会看到不同的对象并导致异常

\u locked
被键入
对象时,不需要一个框。因此,
TryEnter
Exit
方法可以看到相同的对象,并且可以正常工作

关于代码的其他一些注释

  • 在所有情况下,TryEnter都必须与Exit配对,并且出于理智考虑,Exit调用应该位于finally块中。否则,您将引发死锁场景
  • \u locked
    变量仅在遇到异常时设置为
    false
    。如果执行没有产生异常,它将保持为真,并且没有线程将再次进入
    If

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

static object mylock = new object();


为了增加上面的成功-确保锁被释放-TryEnter()和Exit()可以包装在自定义类中,作为对象的扩展,并将委托和超时作为参数

public static class MyMonitor
{

    public static bool TryEnter(this object obj, Action action, int millisecondsTimeout)
    {
            if (Monitor.TryEnter(obj, millisecondsTimeout))
            {
                try
                {
                    action();
                }
                finally
                {
                    Monitor.Exit(obj);
                }
                return true;
            }
            else
            {
                return false;
            }
    }
}
并这样调用,等待1000毫秒以获得锁,或在超时时抛出错误:

if (!_locked.TryEnter(() =>
{
    //Exclusive access code placed here..
}, 1000)) {
    throw new TimeoutException("Timeout waiting for exclusive access");
}

这样,忘记Monitor.Exit()就不是一个选项

是的,当然。但是bool类型不是从System.Object派生的吗?所以它是从Object派生的,但是当在某个地方遇到到Object的转换时,是否使用了装箱操作?这句话正确吗?@Captain,当在键入到
系统的位置中使用任何类型的值类型时,
bool
。对象或接口将发生装箱操作。JaredPar已为您的问题提供了答案。但是你的逻辑似乎有缺陷-如果你进入监视器时带着_locked=true,那么你永远不会退出监视器。哦,当然是的,谢谢VinayCAlso,我想你通常有一个静态对象作为你的锁。@Chris。我的情况不是这样。我需要为类实例而不是类类型提供同步。因此,我不需要静态锁定对象。酷。我确实认为可能是这样,但我想检查一下,这不仅仅是一个打字错误或什么的。:)就我在反射器中看到的情况而言,Monitor.TryEnter(mylock,0)与Monitor.TryEnter(mylock)是相同的。这不是我的经验。我将“0”添加到我的中,它修复了我遇到的问题。@Andrew
静态对象变量mylock
不是有效的变量声明。@DerreckDean-添加
,0
修复了一个错误,这让人惊讶;声明0与省略参数相同:“如果毫秒stimeout等于0,则此方法等效于TryEnter(Object)。@tchelidze-我同意,因此我已编辑以修复声明。
if (!_locked.TryEnter(() =>
{
    //Exclusive access code placed here..
}, 1000)) {
    throw new TimeoutException("Timeout waiting for exclusive access");
}