从不同的线程正确处理事件生成器

时间:2016-08-19 13:53:20

标签: c# multithreading

这是简化的代码,只是说明了我要解决的问题(没有编译它,所以请忽略任何语法错误)。假设我有一个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()

1 个答案:

答案 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
}