我正在尝试确定是否可以在此使用ManualResetEvent
来确保在并发环境中myMethod()
的内部操作从不同时调用。
static volatile bool _syncInitialized = false;
static ManualResetEvent _syncEvent = new ManualResetEvent(false);
static object _syncLock = new object();
void myMethod()
{
lock (_syncLock)
{
if (!_syncInitialized) // sync hasn't started, so
{
_syncInitialized = true;
_syncEvent.Set(); // signal for the first time only
}
}
if (_syncEvent.WaitOne()) // wait for signal
{
_syncEvent.Close();
_syncEvent = new ManualResetEvent(false); // reset to false
// actions that should be forced to run sequentially
}
}
编辑 - 注意我使用的是ManualResetEvent而不是lock(),因为我希望能够添加超时。
答案 0 :(得分:3)
您至少有一次参加比赛的机会。考虑:
线程#1执行_syncEvent.WaitOne()
并成功,然后在它可以执行_syncEvent.Close()
之前被换出。线程#2出现并执行WaitOne()
,并且也成功。
另一个问题是你正在调用Close()
,然后构建一个新实例,显然是一种重置方法。想象一下,你调用Close()
,线程被换出,下一个线程出现并尝试执行WaitOne()
,并抛出异常,因为对象已经关闭。
如果您想重置活动,请致电Reset()
。
您可能无法使用ManualResetEvent
进行此操作。正如其他人所说,ManualResetEvent
用于发信号,而非互斥。
你说你将来要实现超时。如果您只是希望线程在锁上等待一段时间,然后在无法获得锁的情况下退出,请使用接受超时值的Monitor.TryEnter重载之一。例如:
private object _syncObject = new Object();
void MyMethod()
{
if (!Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(5)))
{
return; // couldn't get the lock
}
try
{
// got the lock. Do stuff here
}
finally
{
Monitor.Exit(); // release the lock
}
}
关于你是否真的想在finally
中释放锁定存在争议。如果代码抛出异常,则可能(可能?)您保护的资源现在处于不完整或其他损坏的状态。在这种情况下,您可能不希望让其他线程对其执行操作。无论您是否在例外情况下解锁,都必须根据应用程序的要求做出设计决策。