以下方法对于第一次调用应返回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();
}
答案 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)
您唯一需要确保的是,您锁定的同一对象可供所有需要同步的代码实例访问。除此之外,没问题。