这是简化的代码,只是说明了我要解决的问题(没有编译它,所以请忽略任何语法错误)。假设我有一个ProducerProxy,如:
public class ProducerProxy : IDisposable {
public event EventHandler<EventArgs> NotificationEvent;
private volatile bool itsKeepProducing = true;
public DoStuff() {
Task.Factory.StartNew(() => {
while (itsKeepProducing) {
RaiseNotificationEvent();
Thread.Sleep(100);
}
}
}
public void Dispose() {
itsKeepProducing = false;
DestroySomeStuff();
}
}
假设我现在有一个使用此ProducerProxy的类:
public class Consumer : IDisposable {
private ProducerProxy itsProducerProxy;
public void Consumer() {
itsProducerProxy = new ProducerProxy();
itsProducerProxy.NotificationEvent += OnNotificationEvent;
}
public void Start() {
itsProducerProxy.DoStuff();
}
public void OnNotificationEvent(object sender, EventArgs args) {
DealWithNotification(args); //this could take some time maybe 1-2 seconds
}
public void Dispose() {
//how do I dispose of the producer here?
//I can't just do the following because notifications might still be processing in OnNotification event:
if (itsProducerProxy != null) {
itsProducerProxy.NotificationEvent -= OnNotificationEvent;
itsProducerProxy.Dispose();
itsProducerProxy = null;
}
}
所以我的用例是(是的,它应该使用try/catch
或使用using
来完成,但这会分散注意力 - 只是说明一点)
var consumer = new Consumer();
consumer.Start();
... //do some stuff
consumer.Dispose();
Consumer.Dispose()
的正确/正确的线程安全实现是什么?或者也许是Producer.Dispose()
?
答案 0 :(得分:1)
您可以通过将CancellationToken传入您的流程来使用协作线程取消模式...
public class Consumer : IDisposable {
private ProducerProxy itsProducerProxy;
// how we signal others that we are disposed
private CancellationTokenSource _cts = new CancellationTokenSource();
/* SNIP */
public void OnNotificationEvent(object sender, EventArgs args) {
// We now provide the inner process with the cancellation token
DealWithNotification(_cts.Token);
}
public void Dispose()
{
// not thread safe but you get the gist
if (_cts!= null) {
_cts.Cancel();
_cts.Dispose();
_cts = null;
}
/* SNIP */
}
}
当请求取消时内部过程短路
private void DealWithNotification(CancellationToken token)
{
if(token.IsCancellationRequested) return;
var foo = "omgwtflol" + bar;
if(token.IsCancellationRequested) return;
Thread.Sleep(2);
if(token.IsCancellationRequested) return;
var reallyEveryTime = File.ReadAllBytes(foo);
if(token.IsCancellationRequested) return;
foreach(var b in reallyEveryTime)
{
if(token.IsCancellationRequested) return;
InnerProcess(token);
}
// etc etc etc you get the idea
}