C#读书笔记:线程,任务和同步
前言
學習C#兩個多月了,像當初實習做PHP開發一樣,也是由著一個個Feature需求,慢慢掌握了很多相關的編程技巧。本次主要記錄下學習C# 多線程的相關知識。
?
參考書籍:《Csharp高級編程(第7版)》
?
1.使用線程的原因
?
不過運行多個線程也要注意一些問題:他們可以同時運行,但是如果線程訪問相同的數據,就很容易出問題,必須實現同步機制。
?2.理解線程
?線程是程序中獨立的指令流。C#編寫的程序都有一個入口點(即Main()方法),程序從該方法的第一條開始執行,直到方法返回為止。這種程序結構非常適合用于一個有任務序列的程序,但是程序常常需要同時完成多個任務。
這就要用到多個線程,比如Word的拼寫檢查器的工作原理是這樣的:一個線程等待用戶輸入,另一個線程進行后臺搜索,第3個線程將寫入的數據保存在臨時文件中,第4個線程從Internet上下載其他數據。
理解線程很重要的一點其實是理解線程和進程的關系:
?
3.創建線程的方式
- 異步委托
創建線程的一種簡單地方式是定義委托,并異步調用它。委托是方法的類型安全的引用,它使用線程池來完成異步任務。
代碼實例:
使用投票的例子,并檢查委托是否完成了它的任務。等待異步委托結果的四種方式:
(1)輪詢
Delegate類提供了BeginInvoke()方法,通過其返回類型IAsyncResult ,可以獲取委托的相關信息,并檢驗它是否完成了任務。只要委托沒有完成其任務,程序的主線程就繼續執行while循環。
(2)等待句柄
使用與IAsyncResult 相關聯的等待句柄。使用AsyncWaitHandle屬性可以訪問等待句柄,該屬性可以返回一個WaitHandle類型的對象,它可以等待委托線程完成其任務。
(3)異步回調
(4)Lambda表達式?
using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Diagnostics;namespace Wrox.ProCSharp.Threading {class Program{static int TakesAWhile(int data, int ms){Console.WriteLine("TakesAWhile started");Thread.Sleep(ms);Console.WriteLine("TakesAWhile completed");return ++data;}//要從委托中調用這個方法,必須定義一個有相同參數和返回類型的的委托public delegate int TakesAWhileDelegate(int data, int ms);static void Main(){// synchronous// TakesAWhile(1, 3000);TakesAWhileDelegate d1 = TakesAWhile;// (1)polling輪詢//IAsyncResult ar = d1.BeginInvoke(1, 3000, null, null);//while (!ar.IsCompleted)//{ // // doing something else// Console.Write("."); // Thread.Sleep(50);//}//int result = d1.EndInvoke(ar);//Console.WriteLine("result: {0}", result);// (2)wait handle//IAsyncResult ar = d1.BeginInvoke(1, 3000, null, null);//while (true)//{// Console.Write(".");// if (ar.AsyncWaitHandle.WaitOne(50, false))// {// Console.WriteLine("Can get the result now");// break;// }//}//int result = d1.EndInvoke(ar);//Console.WriteLine("result: {0}", result);// (3)async callback//d1.BeginInvoke(1, 3000, TakesAWhileCompleted, d1);//for (int i = 0; i < 100; i++)//{// Console.Write(".");// Thread.Sleep(50);//}//(4)Lambda expression:可以直接訪問作用域外的變量d1,所以不需要把一個值賦予BeginInvoke()方法的最后一個參數d1.BeginInvoke(1, 3000,ar =>{int result = d1.EndInvoke(ar);Console.WriteLine("result: {0}", result);},null);for (int i = 0; i < 100; i++){Console.Write(".");Thread.Sleep(50);}}static void TakesAWhileCompleted(IAsyncResult ar){if (ar == null) throw new ArgumentNullException("ar");TakesAWhileDelegate d1 = ar.AsyncState as TakesAWhileDelegate;Trace.Assert(d1 != null, "Invalid object type");int result = d1.EndInvoke(ar);Console.WriteLine("result: {0}", result);}} }
運行結果:
?
代碼實例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading;namespace Wrox.ProCSharp.Threading {public class MyThread{private string data;public MyThread(string data){this.data = data;}public void ThreadMain(){Console.WriteLine("Running in a thread, data: {0}", data);}}public struct Data{public string Message;}class Program{static void Main(){FirstThread();//var t1 = new Thread(Prio);//t1.Name = "First";//var t2 = new Thread(Prio);//t2.Name = "Second";//t1.Priority = ThreadPriority.Highest;//t2.Priority = ThreadPriority.Lowest;//t1.Start();//t2.Start();//var t1 = new Thread(ThreadMain);//t1.Name = "MyNewThread1";//t1.IsBackground = true;//t1.Start();//Console.WriteLine("Main thread ending now...");//var d = new Data { Message = "Info" };//var t2 = new Thread(ThreadMainWithParameters);//t2.Start(d);//var obj = new MyThread("info");//var t3 = new Thread(obj.ThreadMain);//t3.Start();}static void Prio(){for (int i = 0; i < 10000; i++){Console.WriteLine("{0}, {1}", Thread.CurrentThread.Name, i);}}static void ThreadMain(){Console.WriteLine("Thread {0} started", Thread.CurrentThread.Name);Thread.Sleep(3000);// Console.WriteLine("Running in the thread {0}, id: {1}.", Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);Console.WriteLine("Thread {0} completed", Thread.CurrentThread.Name);}static void ThreadMainWithParameters(object o){Data d = (Data)o;Console.WriteLine("Running in a thread, received {0}", d.Message);}static void FirstThread(){new Thread(() => Console.WriteLine("Running in a thread, id: {0}", Thread.CurrentThread.ManagedThreadId)).Start();Console.WriteLine("This is the main thread, id: {0}", Thread.CurrentThread.ManagedThreadId);}} }運行結果:
?
代碼實例:
?
using System; using System.Threading;namespace Wrox.ProCSharp.Threading {class Program{static void Main(){int nWorkerThreads;int nCompletionPortThreads;ThreadPool.GetMaxThreads(out nWorkerThreads, out nCompletionPortThreads);Console.WriteLine("Max worker threads: {0}, I/O completion threads: {1}", nWorkerThreads, nCompletionPortThreads);for (int i = 0; i < 5; i++){ThreadPool.QueueUserWorkItem(JobForAThread);}Thread.Sleep(3000);}static void JobForAThread(object state){for (int i = 0; i < 3; i++){Console.WriteLine("loop {0}, running inside pooled thread {1}", i,Thread.CurrentThread.ManagedThreadId);Thread.Sleep(50);}}} }運行結果:
?
?代碼實例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.IO;namespace TaskSamples {class Program{static void Main(){// ParallelDemo();SimpleTask();// ContinuationTask();// ParentAndChild();// ResultsFromTasks();Thread.Sleep(5000);//ParentAndChild();// HierarchyTasks("c:\\");//Parallel.f//Task t1 = new Task(() => Console.WriteLine("running in a task"));//Task t2 = new Task(() => Console.WriteLine("running in a task"));//for (int i = 0; i < 10; i++)//{// Task t1 = new Task(o =>// {// Console.WriteLine("running in a task {0}", Thread.CurrentThread.ManagedThreadId);// Thread.Sleep(500);// Console.WriteLine("still running {0}", Thread.CurrentThread.ManagedThreadId);// }, "data", TaskCreationOptions.None);// // t1.RunSynchronously();// t1.Start();//}//Console.WriteLine("start sleep main");//Thread.Sleep(3000);//Console.WriteLine("main thread");}static void ResultsFromTasks(){var t1 = new Task<Tuple<int,int>>(TaskWithResult, Tuple.Create<int, int>(8, 3));t1.Start();Console.WriteLine(t1.Result);t1.Wait();Console.WriteLine("result from task: {0} {1}", t1.Result.Item1, t1.Result.Item2);}static Tuple<int, int> TaskWithResult(object division){Tuple<int, int> div = (Tuple<int, int>)division;int result = div.Item1 / div.Item2;int reminder = div.Item1 % div.Item2;Console.WriteLine("task creates a result...");return Tuple.Create<int, int>(result, reminder);}static void SimpleTask(){// using task factoryTaskFactory tf = new TaskFactory();Task t1 = tf.StartNew(TaskMethod);// using the task factory via a taskTask t2 = Task.Factory.StartNew(TaskMethod);Console.WriteLine(Thread.CurrentThread.ManagedThreadId);// using Task constructorTask t3 = new Task(TaskMethod);// t3.Start();t3.RunSynchronously();Task t4 = new Task(TaskMethod, TaskCreationOptions.PreferFairness);t4.Start();}static void ContinuationTask(){Task t1 = new Task(DoOnFirst);Task t2 = t1.ContinueWith(DoOnSecond);Task t3 = t1.ContinueWith(DoOnSecond);Task t4 = t2.ContinueWith(DoOnSecond); Task t5 = t1.ContinueWith(DoOnError, TaskContinuationOptions.OnlyOnFaulted);t1.Start();Thread.Sleep(5000);}static void DoOnFirst(){Console.WriteLine("doing some task {0}", Task.CurrentId);Thread.Sleep(3000);}static void DoOnSecond(Task t){Console.WriteLine("task {0} finished", t.Id);Console.WriteLine("this task id {0}", Task.CurrentId);Console.WriteLine("do some cleanup");Thread.Sleep(3000);}static void DoOnError(Task t){Console.WriteLine("task {0} had an error!", t.Id);Console.WriteLine("my id {0}", Task.CurrentId);Console.WriteLine("do some cleanup");}static void ParentAndChild(){Task parent = new Task(ParentTask);parent.Start();Thread.Sleep(2000);Console.WriteLine(parent.Status);Thread.Sleep(4000);Console.WriteLine(parent.Status);}static void ParentTask(){Console.WriteLine("task id {0}", Task.CurrentId);Task child = new Task(ChildTask); // , TaskCreationOptions.DetachedFromParent);child.Start();Thread.Sleep(1000);Console.WriteLine("parent started child");// Thread.Sleep(3000);}static void ChildTask(){// Console.WriteLine("task id {0}, parent: {1}", Task.Current.Id, Task.Current.Parent.Id);Console.WriteLine("child");Thread.Sleep(5000);Console.WriteLine("child finished");}static void TaskMethod(){Console.WriteLine("running in a task");Console.WriteLine("Task id: {0} {1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);}static void ParallelDemo(){// Parallel.For(0, 5, i => Console.WriteLine(i));Parallel.For<string>(0, 20, () => "abcd",(x, ls, str) =>{Console.WriteLine(x);return "defg";},(str) =>{Console.WriteLine("action {0}", str);});ParallelOptions po = new ParallelOptions();}//static void ParentAndChild()//{// TaskFactory factory = new TaskFactory();// var t1 = factory.StartNew(() =>// {// Console.WriteLine("parent task {0}", Task.CurrentId);// factory.StartNew(() =>// {// Console.WriteLine("child task {0}", Task.CurrentId);// Thread.Sleep(2000);// Console.WriteLine("finished child");// }, TaskCreationOptions.AttachedToParent);// Console.WriteLine("finished parent");// });// t1.Wait();//}} }運行結果:
?
代碼實例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks;namespace Wrox.ProCSharp.Threading {class Program{static void Main(){//ParallelFor();//ParallelForeach();ParallelInvoke();}static void ParallelInvoke(){//并行運行多個任務:Parallel.Invoke()方法允許傳遞一個Action委托數組,其中指定應運行的方法Parallel.Invoke(Foo, Bar);}static void Foo(){Console.WriteLine("foo");}static void Bar(){Console.WriteLine("bar");}static void ParallelForeach(){string[] data = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"};//異步方式遍歷ParallelLoopResult result =Parallel.ForEach<string>(data, s =>{Console.WriteLine(s);});Parallel.ForEach<string>(data,(s, pls, l) =>{Console.WriteLine("{0} {1}", s, l);});}static void ParallelFor(){//ParallelLoopResult result =// Parallel.For(0, 10, i =>// {// Console.WriteLine("{0}, task: {1}, thread: {2}", i,// Task.CurrentId, Thread.CurrentThread.ManagedThreadId);// Thread.Sleep(10);// });//Console.WriteLine(result.IsCompleted);//ParallelLoopResult result =// Parallel.For(10, 40, (int i, ParallelLoopState pls) =>// {// Console.WriteLine("i: {0} task {1}", i, Task.CurrentId);// Thread.Sleep(10);// if (i > 15)// pls.Break();// });//Console.WriteLine(result.IsCompleted);//Console.WriteLine("lowest break iteration: {0}", result.LowestBreakIteration);Parallel.For<string>(0, 20,() =>{// invoked once for each threadConsole.WriteLine("init thread {0}, task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);return String.Format("t{0}", Thread.CurrentThread.ManagedThreadId);},(i, pls, str1) =>{// invoked for each memberConsole.WriteLine("body i {0} str1 {1} thread {2} task {3}", i, str1,Thread.CurrentThread.ManagedThreadId,Task.CurrentId);Thread.Sleep(10);return String.Format("i {0}", i);},(str1) =>{// final action on each threadConsole.WriteLine("finally {0}", str1);});}} }運行結果:
?
?
代碼實例:
?
?
ps:在運行書中附帶的sample時,報錯:
經查證,發現這是由于StartupUri中的內容與窗口名稱不一致所導致。
這部分的知識可以參考一篇譯文:WPF教程(十)使用App.xaml
?
轉載于:https://www.cnblogs.com/carsonzhu/p/7207556.html
總結
以上是生活随笔為你收集整理的C#读书笔记:线程,任务和同步的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot学习:在Interi
- 下一篇: c#后台alert出来变乱码问题解决