我应该使用ManualResetEvent作为锁定对象吗?

时间:2011-03-21 09:08:24

标签: c# .net multithreading manualresetevent

以下方法对于第一次调用应返回true,对于任何其他调用应返回false。

有什么问题吗?使用reset事件进行锁定是否安全?

private ManualResetEvent _resetEvent = new ManualResetEvent(false);

public bool AmIFirst()
{
    lock (_resetEvent)
    {
        bool first = !_resetEvent.WaitOne(0);
        if (first)
            _resetEvent.Set();

        return first;
    }
}

修改:在审核完您的评论后,我做了一些更改。由于以前的设计理念,我被ManualResetEvent困住了。实际上我根本不需要它。

class ActionSynchronizer
{
    private Timer _expirationTimer;
    private object _locker = new object();
    private bool _executionRequired = true;

    private SomeDelegate _onExpired = delegate { };

    public ActionSynchronizer(SomeDelegate onExpired)
    {
        _onExpired = onExpired;
        expirationTimer = new Timer(OnExpired, null, 30000, Timeout.Infinite);
    }

    public bool IsExecutionRequired()
    {
        if (!_executionRequired)
            return false;

        lock (_locker)
        {
            if (_executionRequired)
            {
                _executionRequired = false;
                return true;
            }

            return false;
        }
    }

    private void OnExpired(object state)
    {
        if (_executionRequired)
        {
            lock (_locker)
            {
                if (_executionRequired)
                {
                    _executionRequired = false;
                    // http://stackoverflow.com/questions/1712741/why-does-asynchronous-delegate-method-require-calling-endinvoke/1712747#1712747
                    _onExpired.BeginInvoke(_originalAction, EndInvoke, null);
                }
            }
        }
    }
}

// ...
{
    if (_action.Sync.IsExecutionRequired())
        _action.Invoke();
}

4 个答案:

答案 0 :(得分:13)

我会在这里采取不同的路线......

private int counter;
...
if(Interlocked.Increment(ref counter) == 1)
{
     // yes, I'm first
}

线程安全,无锁。或者,如果你担心包围Int32:

if(Interlocked.CompareExchange(ref counter, 1, 0) == 0)
{
     // yes, I'm first
}   

答案 1 :(得分:2)

现在,我只对一个简单的System.Object对象进行了lock(),这个对象是我为了锁定而创建的。

我绝对不会像某个事件那样锁定(),不是因为它不起作用,而是因为我认为在一个对象上使用lock()可能相当令人困惑,它本身就是 < / em>(尽管完全单独)与内核锁定类型操作相关联。

我不清楚你在这里做了什么,但它看起来更像是一个名为Mutex的东西会做得更好。

答案 2 :(得分:1)

我认为最好在对象上使用lock()。

此外,您可以使用“双重检查锁定”来防止多余的线程锁定

e.g。

private object _protection = new object();
private bool _firstTime = true;

public bool AmIFirst()
{
    if (!_firstTime)
        return false;

    lock (_protection)
    {
        if (!_firstTime)
            return false;

        _firstTime = false;
        return true;
    }
}

注意...... - 对于双重检查锁定有一些有趣的评论 - Double-checked locking in .NET - 我还在阅读这篇文章!


另一个注意事项......从你发布的代码片段中看不清楚,但是如果你想要实现一个全局单例,那么http://www.yoda.arachsys.com/csharp/singleton.html上的解决方案4是一个很好的起点

答案 3 :(得分:0)

您唯一需要确保的是,您锁定的同一对象可供所有需要同步的代码实例访问。除此之外,没问题。