TPL Part 4, tplpart

Source: Internet
Author: User

TPL Part 4, tplpart
Simple Continuation

Task. ContinueWith (Task): When the specified Task is completed.

void Main(){Task rootTask = new Task(()=>{Console.WriteLine("root task completed");});root Task.ContinueWith((Task previousTask)=>{Console.WriteLine("continute task completed");}); rootTask.Start(); // waitfor input before exitingConsole.WriteLine("Press enter to finish");Console.ReadLine(); }


Task. ContinueWhenAll (Task []): The sample code is as follows:

 

Task continuation = Task.Factory.ContinueWhenAll<int>(tasks, antecedents =>{foreach(Task<int> t in antecedents) {// dosomething}});


 

 

TaskFactory. continueWhenAny (Task []): when any one of the specified tasks is completed, the code is similar to ContinueWhenAll (in the following code, the execution time of the first Task is printed ):

Task continuation = Task.Factory.ContinueWhenAny<int>(tasks,(Task<int>antecedent) => {//write out a message using the antecedent resultConsole.WriteLine("The first task slept for {0} milliseconds",antecedent.Result);});


Continue options

OnlyOnRanToCompletion

NotOnRanToCompletion: the execution is not completed (canceled or an exception occurs)

OnlyOnFaulted: only when an exception occurs

NotOnFaulted: no exception

OnlyOnCancelled: only canceled

NotOnCancelled: Not canceled

Exception Handling

void Main(){Task rootTask = new Task(()=>{Console.WriteLine("root task completed");throw new Exception("root throwed exception");});rootTask.ContinueWith((Task previousTask)=>{Console.WriteLine("even root throw exception , I still run");}); rootTask.Start(); // waitfor input before exitingConsole.WriteLine("Press enter to finish");Console.ReadLine(); }


In the above Code, the first task throws an exception, and the Continue Task continues to be executed. However, when a Task is Finalized, an exception is thrown.

Solution:

void Main(){Task rootTask = new Task(()=>{Console.WriteLine("root task completed");throw new Exception("root throwed exception");});var t2 = rootTask.ContinueWith((Task previousTask)=>{//if(previousTask.Status== TaskStatus.Faulted){throw previousTask.Exception.InnerException;}Console.WriteLine("even root throw exception , I still run");}); rootTask.Start(); try{t2.Wait();}catch(AggregateException ex){ex.Handle(inner=>{Console.WriteLine("exception handled in main thread"); return true;});} // waitfor input before exitingConsole.WriteLine("Press enter to finish");Console.ReadLine(); }


An exception is thrown in the Task bubble. Wait for the execution of the last Task in the main thread and process the aggresponexception.

Create a subtask

Create a subtask and attach it to the parent Task:

void Main(){ Task parentTask = new Task(() => {Console.WriteLine("parent task started");//create the first child taskTask childTask = new Task(() => {// writeout a message and waitConsole.WriteLine("Child task running");Thread.Sleep(1000);Console.WriteLine("Child task throwed exception");throw new Exception();} ,TaskCreationOptions.AttachedToParent);Console.WriteLine("start child task...");childTask.Start(); Console.WriteLine("parent task ended");});// startthe parent taskparentTask.Start(); // waitfor input before exitingConsole.WriteLine("Press enter to finish");Console.ReadLine();}


1. The parent Task will throw an exception in the subtask.

2. The status of the parent Task is affected by the status of the attached subtask.

Barrier usage

 

class BankAccount {public int Balance {get;set;}} ; void Main(){//create the array of bank accountsBankAccount[] accounts = new BankAccount[6];for(int i = 0;i < accounts.Length; i++) {accounts[i] = new BankAccount();}//create the total balance counterint totalBalance = 0;//create the barrierBarrier barrier = new Barrier(3, (myBarrier) => { // zerothe balancetotalBalance= 0;// sumthe account totalsforeach(BankAccount account in accounts) {totalBalance+= account.Balance;}// writeout the balanceConsole.WriteLine("[From barrier :] Total balance: {0}",totalBalance);});//define the tasks arrayTask[] tasks = new Task[3];// loopto create the tasksfor(int i = 0;i < tasks.Length; i++) {tasks[i]= new Task((stateObj) => {//create a typed reference to the accountBankAccount account = (BankAccount)stateObj;// startof phaseRandom rnd = new Random();for(int j = 0;j < 1000; j++) {account.Balance+= 2;} Thread.Sleep(new Random().Next(3000)); Console.WriteLine("Task {0} waiting, phase {1} ",Task.CurrentId,barrier.CurrentPhaseNumber);//signal the barrier barrier.SignalAndWait(); account.Balance-= 1000;Console.WriteLine("barrier finished .");// endof phaseConsole.WriteLine("Task {0}, phase {1} ended",Task.CurrentId,barrier.CurrentPhaseNumber);//signal the barrierbarrier.SignalAndWait();},accounts[i]);}  // startthe taskforeach(Task t in tasks) {t.Start();}// waitfor all of the tasks to completeTask.WaitAll(tasks);// waitfor input before exitingConsole.WriteLine("Press enter to finish");Console.ReadLine(); }


In the above Code, three barriers and three tasks are opened, and 2000 is added to each account in the Task, and a synchronization signal is sent to the barrier. When the barrier receives three signals, the account is summed and saved. After the barrier completes the logic, the control is handed over to each Task. At this time, each Task minus 1000 on the account and then sums again. The final result is 3000.

If you want to use Cancel to Control barrier behavior, you can also input tokenSource in barrier. token: barrier. signalAndWait (tokenSource. and execute Cancel: tokenSource in the Task. cancel ().

You can call barrier. RemoveParticipant (); To reduce the barrier count.

CountEventDown

Similar to Barrier, the function is to accumulate the number of signals. When the number of semaphores reaches the specified number, set event.

void Main(){ CountdownEvent cdevent = new CountdownEvent(5);//create a Random that we will use to generate// sleepintervalsRandom rnd = new Random();//create 5 tasks, each of which will wait for// arandom period and then signal the eventTask[] tasks = new Task[6];for(int i = 0;i < tasks.Length; i++) {//create the new tasktasks[i]= new Task(() => {// putthe task to sleep for a random period// up toone secondThread.Sleep(rnd.Next(500, 1000));//signal the eventConsole.WriteLine("Task {0} signalling event",Task.CurrentId);cdevent.Signal();});};//create the final task, which will rendezous with the other 5// usingthe count down eventtasks[5] = new Task(()=> {// waiton the eventConsole.WriteLine("Rendezvous task waiting");cdevent.Wait();Console.WriteLine("CountDownEvent has been set");}); // startthe tasksforeach(Task t in tasks) {t.Start();}Task.WaitAll(tasks); // waitfor input before exitingConsole.WriteLine("Press enter to finish");Console.ReadLine(); }


In the above Code, five tasks and one CountDownEvent object with a count of 5 are enabled, and each Task sends signals to CountDownEvent after the Task is completed. After 5 signals are collected, the CountDownEvent has been set is printed.

ManualResetEvent and AutoResetEvent

Those familiar with earlier versions of. net should be familiar with them and used to complete thread synchronization in a multi-threaded environment. The difference is that the former must call reset to restore the signal, while the AutoResetEvent will automatically reset. I will not go into details here.

SemaphoreSlim

void Main(){    SemaphoreSlim semaphore = new SemaphoreSlim(3);//create the cancellation token sourceCancellationTokenSource tokenSource= new CancellationTokenSource(); //create and start the task that will wait on the eventfor(int i = 0;i < 10; i++) {Task.Factory.StartNew((obj)=> { semaphore.Wait(tokenSource.Token);// printout a message when we are releasedConsole.WriteLine("Task {0} released", obj); },i,tokenSource.Token);} //create and start the signalling taskTask signallingTask = Task.Factory.StartNew(() => {// loopwhile the task has not been cancelledwhile(!tokenSource.Token.IsCancellationRequested) {// go tosleep for a random periodtokenSource.Token.WaitHandle.WaitOne(500);//signal the semaphoresemaphore.Release(3);Console.WriteLine("Semaphore released");}// if wereach this point, we know the task has been cancelledtokenSource.Token.ThrowIfCancellationRequested();},tokenSource.Token);// askthe user to press return before we cancel// thetoken and bring the tasks to an endConsole.WriteLine("Press enter to cancel tasks");Console.ReadLine();//cancel the token source and wait for the taskstokenSource.Cancel();// waitfor input before exitingConsole.WriteLine("Press enter to finish");Console.ReadLine(); }


In the above Code, a new SemaphoreSlim object is added and 3 is passed in, and 10 Task threads are opened. When a signal is sent from Semaphore, the Task [I] is printed and release. Enable one signal thread at the same time, each 500 milliseconds release3 Task.

It can be seen that Semaphore is mainly used to select how many tasks can be release at a time.

 

Producer/Consumer (Producer/Consumer Mode)

In the following code, a new BlockingCollection is created and its type is Deposit. Three producer tasks are enabled. Each producer creates 20 Deposit objects and assigns a value of 100 to Amount. Wait for the producer Task to complete execution in the main thread and call the blockingCollection. CompleteAdding () method. Then, open a consumer Task to operate the account object, cyclically judge the blockingCollection. IsCompleted attribute (whether the producer completes the work), fetch the deposit object from the collection, and increase the account balance.

Sample Code:

class BankAccount {public int Balance {get;set;}}class Deposit {public int Amount {get;set;}} void Main(){BlockingCollection<Deposit> blockingCollection= new BlockingCollection<Deposit>(); var producers = new List<Task>();for(int i = 0;i < 3; i++) {var producer = Task.Factory.StartNew((obj) => {//create a series of depositsfor(int j = 0;j < 20; j++) {//create the transfervar randAmount = new Random().Next(100);Deposit deposit = new Deposit { Amount = randAmount};Thread.Sleep(newRandom().Next(200));// placethe transfer in the collectionblockingCollection.Add(deposit);Console.WriteLine(string.Format("Amount: {0} deposit Processed, index: {1}",randAmount, int.Parse(obj.ToString()) +j)); }}, i*20);producers.Add(producer);};//create a many to one continuation that will signal// theend of production to the consumerTask.Factory.ContinueWhenAll(producers.ToArray(),antecedents => {//signal that production has endedConsole.WriteLine("Signalling production end");blockingCollection.CompleteAdding();});//create a bank accountBankAccount account = new BankAccount();//create the consumer, which will update// thebalance based on the depositsTask consumer = Task.Factory.StartNew(() => {while(!blockingCollection.IsCompleted) {Deposit deposit;// tryto take the next itemif(blockingCollection.TryTake(outdeposit)) {//update the balance with the transfer amountaccount.Balance+= deposit.Amount;}}// printout the final balanceConsole.WriteLine("Final Balance: {0}", account.Balance);});// waitfor the consumer to finishconsumer.Wait();// waitfor input before exitingConsole.WriteLine("Press enter to finish");Console.ReadLine(); }


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.