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");
}