【发布时间】:2014-05-19 11:47:41
【问题描述】:
我正在使用一个对象 (EventReceiver),它将成员注册到通过 ctor 导入的对象 (EventSource) 的事件中。 EventReceiverimplements IDisposable 并取消订阅 EventSource。
问题是有不同的线程调用事件处理程序并处理EventReceiver。取消订阅完成后将调用该事件。事件引发和取消订阅之间存在竞争条件。
如何解决?
这是一个演示问题的示例实现:
internal class Program
{
private static void Main(string[] args)
{
var eventSource = new EventSource();
Task.Factory.StartNew(
() =>
{
while (true)
{
eventSource.RaiseEvent();
}
});
Task.Factory.StartNew(
() =>
{
while (true)
{
new EventReceiver(eventSource).Dispose();
}
});
Console.ReadKey();
}
}
public class EventSource
{
public event EventHandler<EventArgs> SampleEvent;
public void RaiseEvent()
{
var handler = this.SampleEvent;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
public class EventReceiver : IDisposable
{
private readonly EventSource _source;
public EventReceiver(EventSource source)
{
this._source = source;
this._source.SampleEvent += this.OnSampleEvent;
}
public bool IsDisposed { get; private set; }
private void OnSampleEvent(object sender, EventArgs args)
{
if (this.IsDisposed)
{
throw new InvalidOperationException("This should never happen...");
}
}
public void Dispose()
{
this._source.SampleEvent -= this.OnSampleEvent;
this.IsDisposed = true;
}
}
在多核处理器上程序启动后几乎直接抛出异常。是的,我知道var handler = this.SampleEvent 将创建事件处理程序的副本,这会导致问题。
我尝试像这样实现RaiseEvent 方法,但没有帮助:
public void RaiseEvent()
{
try
{
this.SampleEvent(this, EventArgs.Empty);
}
catch (Exception)
{
}
}
问题是:如何以多线程的方式实现线程安全的事件注册和注销?
我的期望是取消注册将被暂停,直到当前触发的事件完成(也许这只能使用第二个实现)。但我很失望。
【问题讨论】:
-
看起来
OnSampleEvent和Dispose应该通过互斥锁同步。
标签: c# multithreading events event-handling