public static void SafePost <TIn>(this ITargetBlock <TIn> target, TIn item, int interval = 200, int retryCount = 3) { bool posted = target.Post(item); if (posted) { return; } if (target.Completion.IsCompleted) { string msg = string.Format( "Safe post to {0} failed as the block is {1}", Utils.GetFriendlyName(target.GetType()), target.Completion.Status); throw new PostToBlockFailedException(msg); } for (int i = 1; i <= retryCount; i++) { Thread.Sleep(interval * i); posted = target.Post(item); if (posted) { return; } } throw new PostToBlockFailedException( string.Format("Safe post to {0} failed after {1} retries", Utils.GetFriendlyName(target.GetType()), retryCount)); }
internal static bool TestBoundingTarget <TInput, TOutput>(ITargetBlock <TInput> target, bool greedy) { Console.WriteLine("* TestBoundingTarget {0} ({1})", target.GetType().Name, greedy ? "greedy" : "non-greedy"); bool passed = true; bool localPassed = true; int i; var send1 = new Task <bool> [BOUNDED_CAPACITY]; var send2 = new Task <bool> [BOUNDED_CAPACITY]; if (target is ActionBlock <TInput> ) { _m_pause = new ManualResetEventSlim(); } // Send messages up to the bounding capacity for (i = 0; localPassed && i < BOUNDED_CAPACITY; i++) { // All should be accepted immediately in greedy mode send1[i] = target.SendAsync(default(TInput)); if (greedy) { localPassed = send1[i].Wait(0) && send1[i].Result; } } // In non-greedy mode, all should be accepted afterwards if (!greedy) { localPassed = Task.WaitAll(send1, COMPLETE_TIMEOUT); } passed &= localPassed; Assert.True(localPassed, string.Format("FAILED to send up to capacity ({0}) at iteration {1}", BOUNDED_CAPACITY, i)); // Send one more message - it should be postponed (not consumed) send2[0] = target.SendAsync(default(TInput)); localPassed = !send2[0].Wait(NOT_COMPLETED_TIMEOUT) || target is BroadcastBlock <TInput>; // TODO: How to make BroadcastBlock reliably postpone messages? passed &= localPassed; Assert.True(localPassed, "FAILED to postpone the excess message"); // Unblock at least one message if (target is ActionBlock <TInput> ) { _m_pause.Set(); } else { TOutput item; ((IReceivableSourceBlock <TOutput>)target).TryReceive(out item); } // Now the excess item should be consumed in greedy mode and postponed in non-greedy mode localPassed = send2[0].Wait(greedy ? COMPLETE_TIMEOUT : NOT_COMPLETED_TIMEOUT); if (!greedy) { localPassed = !localPassed; } passed &= localPassed; Assert.True(localPassed, "FAILED to consume the excess message after unblocking"); if (target is BatchBlock <TInput> ) { // Let the task that consumed the excess message go away if (greedy) { Task.Delay(COMPLETE_TIMEOUT).Wait(); } // Send messages up to the bounding capacity for (i = 1; localPassed && i < BOUNDED_CAPACITY; i++) { // All should be accepted immediately in greedy mode send2[i] = target.SendAsync(default(TInput)); if (greedy) { localPassed = send2[i].Wait(0) && send2[i].Result; } } // In non-greedy mode, all should be accepted afterwards if (!greedy) { localPassed = Task.WaitAll(send2, COMPLETE_TIMEOUT); } passed &= localPassed; Assert.True(localPassed, string.Format("FAILED to send up to capacity ({0}) at iteration {1} AFTER unblocking", BOUNDED_CAPACITY, i)); } return(passed); }
public IDisposable LinkTo(ITargetBlock <TOut> target, DataflowLinkOptions linkOptions) { target = new TargetHookDelegate <TOut>(Name + " -> " + target.GetType().Name, this, target, _sync); return(_local.LinkTo(target)); }
public static void SafePost <TIn>(this ITargetBlock <TIn> target, TIn item, int interval = 200, int retryCount = 3) { bool posted = target.Post(item); if (posted) { return; } for (int i = 1; i <= retryCount; i++) { Thread.Sleep(interval * i); posted = target.Post(item); if (posted) { return; } } throw new PostToBlockFailedException("Safe post to " + Utils.GetFriendlyName(target.GetType()) + " failed"); }