0

我正在尝试确定是否可以使用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() 因为我希望能够添加超时,可能。

4

1 回答 1

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. 如果代码抛出异常,那么您保护的资源可能(很可能?)现在处于不完整或损坏状态。在这种情况下,您可能不想让其他线程对其进行操作。是否在遇到异常时释放锁是您必须做出的设计决定,与您的应用程序的要求一致。

于 2012-12-29T20:58:33.370 回答