2

MaxDegreeOfParallelism が 1 であるにもかかわらず、並列処理が発生しているように見える ActionBlock への投稿時に、予期しない動作が見られます。これがシナリオです。

ActionBlock に投稿するクラスは次のようになります。

public class ByteHandler {
...
   public ByteHandler(ByteHandlingCallback delegateCallback){
       _byteHandlingActionBlock = new ActionBlock<byte[]>(bytes => delegateCallback.HandleBytes(bytes));
   }


   public void HandleBytes(byte[] bytes){
       _byteHandlingActionBlock.Post(bytes);
   }

下流では、バイトをオブジェクトにデシリアライズし、それらのオブジェクト (通知と呼びましょう) をそのタイプに応じてハンドラーに渡します。

public class NotificationHandler{
   private readonly Dictionary<string, AutoResetEvent> _secondNoticeReceivedEvents;

   public void HandleInitialNotification(InitialNotification notification){
       var secondNoticeReceivedEvent = new AutoResetEvent(false);
       if (!_secondNoticeReceivedEvents.TryAdd(notification.ID, secondNoticeReceivedEvent)) return;

       DoSomethingDownstream(notification);

       if (secondNoticeReceivedEvent.WaitOne(_timeout))
            DoSomethingElseDownstream();
       else
            throw new Exception("Second notification not received within timeout!");

       _secondNoticeReceivedEvents.TryRemove(notification.ID, out secondNoticeReceivedEvent);
   }

   public void HandleSecondNotification(SecondNotification notification){
       AutoResetEvent secondNoticeReceivedEvent;
       if (_secondNoticeReceivedEvents.TryRemove(notification.ID, out secondNoticeReceivedEvent))
            secondNoticeReceivedEvent.Set();
   }

このハンドラーには致命的なバグがあります: InitialNotifications は対応する SecondNotifications の前に到着しますが、HandleInitialNotification は終了する前に HandleSecondNotification を待機するため、スレッドは HandleSecondNotification に到達しません。

通常、HandleInitialNotification は、HandleSecondNotification の待機がタイムアウトになるまでブロックされ、保留中の SecondNotification が同じスレッドで処理されて実行が続行されます。これは通常、ログに表示されるものです。

2013-07-05 13:27:25,755 [13] INFO  Received InitialNotification for: XX
2013-07-05 13:27:35,758 [13] WARN  Second notification not not received for XX within timeout!
2013-07-05 13:27:35,761 [13] INFO  Received SecondNotification for: XX

これは、コードが意図された動作方法ではありませんが、記述された方法を考えると、SecondNotification を待って常にタイムアウトする必要があります。ただし、時折、HandleInitialNotification がタイムアウトする前に完了し、HandleSecondNotification が別のスレッドでタイムリーに処理されることもあります。

2013-07-05 13:38:13,232 [56] INFO  Received InitialNotification for: YY
2013-07-05 13:38:13,258 [11] INFO  Received SecondNotification for: YY

デフォルトの ActionBlock を使用しているため、MaxDegreeOfParallelism は 1 である必要があります。では、ActionBlock に投稿された元のスレッドがブロックしている間に、2 番目のスレッド (ActionBlock で発生) が SecondNotification を取得できるのはなぜでしょうか?

4

1 に答える 1