// ********* protected virtual void OnAllTasksCompleted(CompletedEventArgs e) { EventHandler <CompletedEventArgs> handler = AllTasksCompleted; if (handler != null) { handler(this, e); } }
/* * Bounding is also used to introduce artificial latency into the WithoutBlocking sample. * One of the major differences between WithoutBlocking and WithBlocking are the TryAdd and TryTake statements. * Examination of the parameters reveals timeout values in milliseconds or in a defined TimeSpan class. * WithoutBlocking Tasks, block for small increments of time before continuing execution. * The sample code utilizes seconds or half seconds, but given that a Timespan can be a small interval, a developer is not constrained to milliseconds. * Because a method can return before the timeout interval, WithoutBlocking also excludes the try/catch code. * This is an interesting sample to tinker with. * Changing the Sleep values in Task1 and Task2 has some interesting effects and really demonstrates shifting bottlenecks in code. */ public void WithoutBlocking(int boundvalue, int stage1timeout, int stage2timeout, CancellationTokenSource tokenSource) { int[] items = { 1, 2, 3, 4, 5, 6, 7, 8 }; var startTime = DateTime.Now; message += "Producer...Starting...WithoutBlocking" + Environment.NewLine; var stage1 = new BlockingCollection <int>(); var stage2 = new BlockingCollection <int>(boundvalue); //Required to force the TryAdd delay //Pulls numbers from the array var task0 = Task.Factory.StartNew(() => { foreach (int i in items) { if (tokenSource.IsCancellationRequested) { break; } stage1.Add(i); message += ("T" + Thread.CurrentThread.ManagedThreadId.ToString() + "Producer - Add:" + i.ToString() + " Count=" + stage1.Count.ToString() + Environment.NewLine); } if (tokenSource.IsCancellationRequested) { message += "Producer - Cancellation requested, exiting..." + Environment.NewLine; } else { message += "Producer - Loaded all items into stage 1..." + Environment.NewLine; stage1.CompleteAdding(); } }, tokenSource.Token); //Reads and passes data onto next stage var task1 = Task.Factory.StartNew(() => { int i = -1; while (!stage1.IsCompleted) { if (tokenSource.IsCancellationRequested) { break; } if (stage1.TryTake(out i, stage1timeout)) { message += ("T" + Thread.CurrentThread.ManagedThreadId.ToString() + " Consumer1 - Stage 1 Process: " + i.ToString() + " elapsed " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString() + Environment.NewLine); while (!stage2.TryAdd(i, new TimeSpan(0, 0, 0, 0, stage2timeout))) { message += ("T" + Thread.CurrentThread.ManagedThreadId.ToString() + " Consumer1 - Attempt to add " + i.ToString() + " expired elapsed " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString() + Environment.NewLine); } //Pause X miliseconds simulating work //change to as high as 2000 and low as 100 //to see impact Thread.Sleep(new TimeSpan(0, 0, 0, 0, 2000)); } else { message += ("T" + Thread.CurrentThread.ManagedThreadId.ToString() + " Consumer1 - TIMEOUT Stage1 - trytake: " + i.ToString() + " elapsed " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString() + Environment.NewLine); } } if (tokenSource.IsCancellationRequested) { message += "Consumer1 - Cancellation requested, exiting..." + Environment.NewLine; } else { message += "Consumer1 - Emptied all items from Stage 1..." + Environment.NewLine; stage2.CompleteAdding(); } }, tokenSource.Token); //Reads prints data var task2 = Task.Factory.StartNew(() => { int i = -1; while (!stage2.IsCompleted) { if (tokenSource.IsCancellationRequested) { break; } if (stage2.TryTake(out i, 300)) { message += ("T" + Thread.CurrentThread.ManagedThreadId.ToString() + " Consumer2 - Stage 2 Process: " + i.ToString() + " elapsed " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString() + Environment.NewLine); //Pause a little over half second to simulate work Thread.Sleep(new TimeSpan(0, 0, 0, 0, 600)); } else { message += ("T" + Thread.CurrentThread.ManagedThreadId.ToString() + " Consumer2 - TIMEOUT Stage2 [Try take]: exceeded at " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString() + Environment.NewLine); } } }, tokenSource.Token) .ContinueWith((prevtask) => { message += "WithoutBlocking Example - Completed." + Environment.NewLine; // Simple test for checking propagation of exceptions. // This works fine, simply check the task.WhenAll result, it will say faulted with a list of the exceptions thrown...easy //throw new System.NotImplementedException(); }, tokenSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default); Task.WhenAll(task0, task1, task2) .ContinueWith((prevTask) => { CompletedEventArgs e = new CompletedEventArgs(prevTask); OnAllTasksCompleted(e); }); }