public void Run() { Console.WriteLine("Starting Task Parallel Library (TPL) review ..."); bool runTaskInstantiationOptions = false; if (runTaskInstantiationOptions) { //Tasks can be created implicitly (i.e., Parallel.Invoke) or explicitly (see below). //Creating tasks implicitly Parallel.Invoke(() => Console.WriteLine("Implicit taks creation - Parallel.Invoke called.")); Parallel.Invoke(() => PrintMsgAction("Implicit taks creation - Parallel.Invoke called with Action ...")); //You can create and run multiple tasks (in parallel) in same invoke statement Parallel.Invoke ( () => AddIntegers(3, 5), () => PrintMsgAction("Implicit taks creation - Parallel.Invoke with multiple tasks") ); //The three options for instantiating a task explicitly, i.e., new Task followed by Start, Task.Run and // Task.Facory.StartNew Task ePattern1 = new Task(() => PrintMsgAction("Explicit task instantiation - new Task ...")); ePattern1.Start(); Task ePattern2 = Task.Run(() => PrintMsgAction("Explicit task instantiation - Task.Run ...")); Task ePattern3 = Task.Factory.StartNew(() => PrintMsgAction("Explicit task instantiation - Task.Facory.StartNew ...")); Task.WaitAll(ePattern1, ePattern2, ePattern3); //Note, Task.Run and Task.Factory.StartNew are convenience methods. For example, Task.Run uses the default scheduler, //and the StartNew is used when you want to create and start in the same line of code //When creating a task, the delegate can be a named delegate, an anonymous method or a lambda expression Task dPattern1A = new Task(() => PrintMsgAction("Task with named action")); //using named (Action() delegate Task dPattern1B = new Task(() => PrintMsg("Task with named method")); //using named method Task dPattern2 = new Task(() => { Console.WriteLine("Task with anonymous method"); }); Task dPattern3 = new Task(() => Console.WriteLine("Task with lambda expression")); //using lambda expression dPattern1A.Start(); dPattern1B.Start(); dPattern2.Start(); dPattern3.Start(); Task.WaitAll(dPattern1A, dPattern1B, dPattern2, dPattern3); //Example: using StartNew to pass in state List <Task> statefulTasks = new List <Task>(); for (int i = 0; i < 5; i++) { statefulTasks.Add( Task.Factory.StartNew((Object obj) => { TaskState state = obj as TaskState; state.ThreadNum = Thread.CurrentThread.ManagedThreadId; Console.WriteLine(String.Format("Task {0} is running", state.Name)); }, new TaskState() { Name = String.Format("Stateful Task {0}", i + 1) } )); } Task.WaitAll(statefulTasks.ToArray()); foreach (Task task in statefulTasks) { TaskState state = task.AsyncState as TaskState; Console.WriteLine(String.Format("[Stateful task execution info] Name = {0}, thread = {1}, status = {2}", state.Name, state.ThreadNum, task.Status)); } //Example: Specifying task scheduling options //Available options None, PreferFairness (scheduling), LongRunning, AttachdToParent (for sub-tasks), ... Task rcoTask = new Task(() => PrintMsg("runCreationOptions task running ..."), TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness); rcoTask.Start(); Task.WaitAll(rcoTask); } bool runTaskParamsAndResult = false; if (runTaskParamsAndResult) { //Recall the two types of Tasks, i.e., one that returns a void and one that returns a result (i.e., Task<TResult>). (So the type //declaration does not include the arguments.) int two = 2; Task prTask1 = new Task((x) => { int intx = (int)x; Console.WriteLine(@"Task params and results: {0} squared is {1}", intx, intx * intx); }, two); prTask1.Start(); Task <int> prTask2 = new Task <int>((x) => { return((int)x * (int)x); }, two); prTask2.Start(); Task.WaitAll(prTask1, prTask2); if (prTask2.Status == TaskStatus.RanToCompletion) { Console.WriteLine(@"The result from prTask2 is: {0}", prTask2.Result); } else { Console.WriteLine(@"The completion status of prTask2 is: {0}", prTask2.Status); } string prMsg1 = "Task Parameters and Results section - using a delegate"; Task prTask3 = Task.Factory.StartNew(() => PrintMsgAction(prMsg1)); Task.WaitAll(prTask3); Task <int> prTask4 = Task <int> .Factory.StartNew(() => ReturnSum(1, 3)); Task.WaitAll(prTask4); Console.WriteLine(@"[Params and Results Section] The result from ReturnSum(1,3) is {0}", prTask4.Result); Task <int> prTask5 = Task <int> .Factory.StartNew(() => ReturnSumFuncDelegate(2, 4)); Task.WaitAll(prTask5); Console.WriteLine(@"[Params and Results Section] The result from ReturnSumFuncDelegate(2,4) is {0}", prTask5.Result); //Note: we can use the '=> (...)' to pass arguments to the task constructor, if any. //Below we use a the constructor that takes a state object to pass in variables to the task. Task <int> prTask6 = Task.Factory.StartNew((Object obj) => { TaskParams1 taskParams1 = obj as TaskParams1; return(taskParams1.Val1 + taskParams1.Val2); }, new TaskParams1() { Val1 = 3, Val2 = 6 }); Console.WriteLine(@"[Params and Results Section] Using state object to pass parameters, 3 + 6 is {0}", prTask6.Result); // For more details on returning a result from a task see // https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-return-a-value-from-a-task // Note: Task.Result should be avoided when using async as this could result in a deadlok. More on this later. //[TBD]When you create a task and pass in a delegate, can you also pass state to the task method? If so, how do you //acess the state object from withing that method. } bool runTaskCustomization = false; if (runTaskCustomization) { //Task.StartNew provides more control such as, specifying the scheduler, providing state, etc. //TBD string w = ""; Task temp = new Task((o) => { Console.WriteLine(0); }, w); //With Task.Run as this is a single statment you cannot pass any parametrs. //You can access variables in the task but be aware as the task in on a separate thread so multiple //threads may update the same variable. int i = 1; int iCopy = i; //Create a copy for the task, just to be on the safe side. Task.Run(() => ReturnSum(iCopy, 2)); var startNew = Task <string> .Factory.StartNew((o) => ("holy " + o), "cow"); //https://www.dotnetforall.com/correct-way-provide-input-parameter-task/ } bool runTaskCulture = false; if (runTaskCulture) { //Unless you have sepecified the culture for all threads using CultureInfo.DefaultThreadCurrentCulture, each //thread gets its culture from the System Culture. (Note that a new thread does not get its culture from the //the thread that created it. ) //Starting from .NET 4.6 onwards each task inherits its culture from it's calling thread. } bool runTaskContinue = false; if (runTaskContinue) { //Take a palindrome, unformat, reverse each word, construct palindrome and format. string originalStr = "Able was I I saw Elba"; Task <string[]> deconstructPalindrome = Task.Factory.StartNew((Object obj) => { return((obj as string).Split("")); }, originalStr); Task <string[]> reverseWords = deconstructPalindrome.ContinueWith((x) => { string[] words = x.Result as string[]; string[] reversedWords = new string[words.Length]; for (int i = 0; i < words.Length; i++) { char[] chars = words[i].ToCharArray(); Array.Reverse(chars); reversedWords[i] = new string(chars); } return(reversedWords); }); Task <string> makeSentence = reverseWords.ContinueWith((x) => { return(String.Join(" ", x.Result)); }); Task.WaitAll(makeSentence); Console.WriteLine(@"[TaskContinueWith] Palindrome of <{0}> is <{1}>", originalStr, makeSentence.Result); //Note: we could string the three tasks together in a single statements as follows: //Task<string[]> deconstructPalindrome = Task.Factory.StartNew((Object obj) => {...}, ...).ContinueWith(...) } bool runTaskSyncAndManagement = true; if (runTaskSyncAndManagement) { //Child tasks //Detached child task example Task <Task> parentTask = Task.Factory.StartNew(() => { Task childTask = Task.Factory.StartNew(() => Thread.SpinWait(2000)); return(childTask); }); Task.WaitAll(parentTask); Task detachedChild = parentTask.Result; Console.WriteLine(@"[Detached Child] Parent task status is {0}. Detached child task status is {1}", parentTask.Status, detachedChild.Status); Task.WaitAll(detachedChild); Console.WriteLine(@"[Detached Child] After WaitAll(detachedChild), child task status is {0}", detachedChild.Status); //Attached child task example. (Note, parent cannot return the child task as its not available at end of task) parentTask = Task.Factory.StartNew(() => { Task childTask = Task.Factory.StartNew(() => { Thread.SpinWait(2000); }, TaskCreationOptions.AttachedToParent); return(childTask); }); Task.WaitAll(parentTask); Task attachedChild = parentTask.Result; Console.WriteLine(@"[Attached Child] Parent task status is {0}. Attached child task status is {1}", parentTask.Status, attachedChild.Status); //Task cancellation .... Console.WriteLine("Runninng task cancellation ..."); CancellationTokenSource cts = new CancellationTokenSource(); Task cancelTask = null; //// Involuntary task cancellation //// *** Note, currently this is not possible. The task needs to do monitor token and terminate upon request. //cancelTask = new Task(() => PrintMsgLoopAction("Testing involuntary cancel"), cts.Token); //cancelTask.Start(); //Thread.Sleep(3000); //cts.Cancel(); //while (!cancelTask.IsCanceled && !cancelTask.IsCompleted) //{ //} cts = new CancellationTokenSource(); // Managed task cancellation cancelTask = new Task(() => PrintMsgLoopActionWithGracefulCancel("Testing graceful cancel", cts.Token), cts.Token); cancelTask.Start(); Thread.Sleep(3000); cts.Cancel(); try { cancelTask.Wait(cts.Token); //Task.WaitAll(new Task[] {cancelTask}, cts.Token); } catch (OperationCanceledException ocex) { //Note: An exception *is* thrown when waiting on a task that is cancelled } Console.WriteLine(String.Format("Task Cancellation completed. Task status = {0}, IsCancelled = {1}", cancelTask.Status, cancelTask.IsCanceled)); //Taks wait (WaitAll, WaitAny) Console.WriteLine("Runninng task wait ..."); Task.Run(() => PrintMsg("Task 1")).Wait(); // will wait before moving on to next line of code Task task2 = Task.Run(() => PrintMsg("Task 2")); // will start task and move on to next line of code Task task3 = Task.Run(() => PrintMsg("Task 3")); // will start task and move on to next line of code Task.WaitAll(task2, task3); Console.WriteLine(String.Format("Tasks wait completed. Task2 status = {0}, Task3 status = {1}", task2.Status, task3.Status)); //[Example TBD] WhenAll - asynchronously waits for Task or Task<TResult> objects to finish. This is an asynchronous version of (blocking) WaitAll. //[Example TBD] WhenAny //[Example TBD] Task.Delay - produces a task object that finishes after given period of time. //[Example TBD] Task(T).FromResult } Console.WriteLine("Completed TaskBasics."); }
private async Task <int> SumTaskParams1Vals(TaskParams1 taskParams1) { return(taskParams1.Val1 + taskParams1.Val2); }