2015-12-30 69 views
0

我有一个引发多个事件的服务,其中一些可以同时引发。我需要处理这些事件并根据事件参数运行可能长时间运行的方法。
我所做的是创建一个BlockingCollection<T>,它将存储事件一个Task,它将一直保持一个事件,直到它将被发信号停止使用CancellationTokenSource
我担心的是我没有足够好地处理同步。
这是处理一切类(它用作WPF ViewModel):多事件和多线程

public class EventsTest 
{ 
    //private fields 
    private BlockingCollection<IoEventArgs> _queue; 
    private CancellationTokenSource _tokenSource; 
    private IoService _ioService; 
    private Task _workerTask; 
    private static EventWaitHandle _eventWaiter; 

    public EventsTest() 
    { 
     _queue = new BlockingCollection<IoEventArgs>(); 
     _tokenSource = new CancellationTokenSource(); 
     _eventWaiter = new EventWaitHandle(false, EventResetMode.AutoReset); 

     //this is the object that raises multiple events 
     _ioService = new IoService(); 
     _ioService.IoEvent += _ioService_IoEvent; 

     //Start Listening 
     var t = Task.Factory.StartNew(StartListening, _tokenSource, TaskCreationOptions.LongRunning); 
    } 

    //IO events listener 
    private void _ioService_IoEvent(string desc, int portNum) 
    { 
     //add events to a blocking collection 
     _queue.Add(new IoEventArgs() { Description = desc, PortNum = portNum }); 
    } 

    private void StartListening(object dummy) 
    { 
     //process the events one at a time 
     while (!_tokenSource.IsCancellationRequested) 
     { 
      var eve = _queue.Take(); 
      switch (eve.PortNum) 
      { 
       case 0: 
        LongRunningMethod(eve.Description); 
        break; 
       case 1: 
        //invoke a long running method 
        break; 
       default: 
        break; 
      } 
     } 
    } 

    //sample long running method 
    private void LongRunningMethod(string data) 
    { 
     _eventWaiter.WaitOne(10000); 
    } 
} 

我怎样才能让这个过程更健壮的线程安全的条款?
在每个方法实现周围添加一个lock是否会提高过程的安全性?

回答

1

您的.Take()不会被取消,因此您可能会永远在那里等待。

你可以通过在令牌:

var eve = _queue.Take(_tokenSource); 

但随后你就必须处理异常。

更好的方法是TryTake(out eve,1000,_tokenSource)并用返回的布尔值操纵。

或者忘记的CancellationToken,只是使用AddingComplete()

+0

不允许传递'_tokenSource':'无法从'System.Threading.CancellationTokenSource'转换为'System.Threading.CancellationToken''。我需要为此创建一个单独的'CancellationToken'吗? – Yoav

+0

是的,源具有.Token属性。 –

0

这听起来像是一种情况,微软的反应框架是一个更好的选择。

您的代码应该是这样的:

public class EventsTest 
{ 
    private IDisposable _subscription; 

    public EventsTest() 
    { 
     IoService ioService = new IoService(); 

     _subscription = 
      Observable 
       .FromEvent<IoEvent, IoEventArgs>(
        a => ioService.IoEvent += a, a => ioService.IoEvent -= a) 
       .Subscribe(eve => 
       { 
        switch (eve.PortNum) 
        { 
         case 0: 
          LongRunningMethod(eve.Description); 
          break; 
         case 1: 
          //invoke a long running method 
          break; 
         default: 
          break; 
        } 
       }); 
    } 

    private void LongRunningMethod(string data) 
    { 
    } 
} 

这应自动确保多个事件进行排队,永远不会重叠。如果出现问题,请在.Subscribe(...)之前拨打.Synchronize(),然后完美运行。

当你想取消事件只需致电_subscription.Dispose(),它会全部为你清理。

NuGet“Rx-Main”获取您需要的位。