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

发布于 2024-10-25 04:55:44 字数 1783 浏览 2 评论 0原文

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

是不是有什么问题呢?使用重置事件进行锁定安全吗?

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

The method below should return true for the first call, and false for any other call.

Is there any problem with it? Is it safe to use the reset event for locking?

private ManualResetEvent _resetEvent = new ManualResetEvent(false);

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

        return first;
    }
}

Edit: I made some changes after reviewing you're remarks. I was stuck on ManualResetEvent due to former design idea. I actually don't need it at all.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

还如梦归 2024-11-01 04:55:44

我会在这里走不同的路线...

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
}   

I would go a different route here...

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

Thread safe, no locks. Or if you are worried about wrapping around Int32:

if(Interlocked.CompareExchange(ref counter, 1, 0) == 0)
{
     // yes, I'm first
}   
萌面超妹 2024-11-01 04:55:44

如今,我只对一个简单的 System.Object 对象进行 lock() ,我创建该对象只是为了锁定。

我绝对不会对诸如事件之类的东西使用 lock() ,不是因为它不起作用,而是因为我认为在它本身的对象上使用 lock() 可能会相当混乱本身 (尽管完全独立)与内核锁定类型操作相关。

我不清楚你实际上在这里做什么,但它看起来很像一个名为互斥体可能会做得更好的事情。

Nowadays, I only ever lock() on a simple System.Object object which I've created just for locking with.

I definitely wouldn't lock() on something like an Event, not because it wouldn't work, but because I think it's potentially rather confusing to be using lock() on an object which it is itself (though completely separately) associated with kernel locking type operations.

I'm not clear what you're actually doing here, but it looks rather like something which a named Mutex might do better.

∞梦里开花 2024-11-01 04:55:44

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

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

例如

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

注意... - 关于双重检查锁定有一些有趣的评论 - .NET 中的双重检查锁定 - 我仍在阅读此内容!


另请注意...从您发布的代码片段中尚不清楚,但如果您希望实现全局单例,则解决方案 4 位于 http://www.yoda.arachsys.com/csharp/singleton.html 是一个很好的起点

I think it's better to use lock() for this on an object.

Also, you can prevent excess thread locking by using a "double-checked locking"

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

Note... - there's some interesting comments on double-checked locking - Double-checked locking in .NET - I'm still reading up on this!


Another note... its not clear from the code snippet you posted, but if you are looking to implement a global singleton then solution 4 on http://www.yoda.arachsys.com/csharp/singleton.html is a good place to start

全部不再 2024-11-01 04:55:44

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

The only thing you need to make sure is that the same object you lock on is accessible to all instances of the code that needs synchronizing. Other than that, no problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文