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 を取得できるのはなぜでしょうか?