C# 线程的各种知识,和使用方法
C#的各种使用方法的代码,在学习中整理过来的。标记一下。但是线程不是越多越好,每创建一个线程都要1MB的虚拟内存,而且,线程数量超过CPU(核心)的数量的话会有线程间的上下文切换,大概30MS的样子,这会浪费很多资源并且降低性能啊。不过C#的线程池是个不错的选择,但是最好不要给他设置上下限,因为这有可能会给任务带来阻塞。
1、
#region ThreadTest One public class Cell { int cellContents; // Cell对象里边的内容 bool readerFlag = false; // 状态标志,为true时可以读取,为false则正在写入 public int ReadFromCell() { lock(this) // Lock关键字保证了什么,请大家看前面对lock的介绍 { if (!readerFlag)//如果现在不可读取 { try { //等待WriteToCell方法中调用Monitor.Pulse()方法 Monitor.Wait(this); } catch (SynchronizationLockException e) { Console.WriteLine(e); } catch (ThreadInterruptedException e) { Console.WriteLine(e); } } Console.WriteLine("Consume: {0}",cellContents); readerFlag = false; //重置readerFlag标志,表示消费行为已经完成 Monitor.Pulse(this); //通知WriteToCell()方法(该方法在另外一个线程中执行,等待中) } return cellContents; } public void WriteToCell(int n) { lock(this) { if (readerFlag) { try { Monitor.Wait(this); } catch (SynchronizationLockException e) { //当同步方法(指Monitor类除Enter之外的方法)在非同步的代码区被调用 Console.WriteLine(e); } catch (ThreadInterruptedException e) { //当线程在等待状态的时候中止 Console.WriteLine(e); } } cellContents = n; Console.WriteLine("Produce: {0}",cellContents); readerFlag = true; Monitor.Pulse(this);//通知另外一个线程中正在等待的ReadFromCell()方法 } } } public class CellProd { Cell cell; // 被操作的Cell对象 int quantity = 1; // 生产者生产次数,初始化为1 public CellProd(Cell box, int request) { //构造函数 cell = box; quantity = request; } public void ThreadRun() { for(int looper=1; looper<=quantity; looper++) cell.WriteToCell(looper); //生产者向操作对象写入信息 } } public class CellCons { Cell cell; int quantity = 1;//消费者的消费次数 public CellCons(Cell box, int request) { cell = box; quantity = request; } public void ThreadRun() { int valReturned; for (int looper = 1; looper <= quantity; looper++) valReturned = cell.ReadFromCell();//消费者从操作对象中读取信息 } } public class MonitorSample { public static void Main(String[] args) { int result = 0; //一个标志位,如果是0表示程序没有出错,如果是1表明有错误发生 Cell cell = new Cell(); //下面使用cell初始化CellProd和CellCons两个类,生产和消费次数均为20次 CellProd prod = new CellProd(cell, 20); CellCons cons = new CellCons(cell, 20); Thread producer = new Thread(new ThreadStart(prod.ThreadRun)); Thread consumer = new Thread(new ThreadStart(cons.ThreadRun)); //生产者线程和消费者线程都已经被创建,但是没有开始执行 try { producer.Start(); consumer.Start(); producer.Join(); consumer.Join(); Console.ReadLine(); } catch (ThreadStateException e) { //当线程因为所处状态的原因而不能执行被请求的操作 Console.WriteLine(e); result = 1; } catch (ThreadInterruptedException e) { //当线程在等待状态的时候中止 Console.WriteLine(e); result = 1; } //尽管Main()函数没有返回值,但下面这条语句可以向父进程返回执行结果 Environment.ExitCode = result; } } #endregion
2、
#region ThreadTest Two 这是用来保存信息的数据结构,将作为参数被传递 public class SomeState { public int Cookie; public SomeState(int iCookie) { Cookie = iCookie; } } public class Alpha { public Hashtable HashCount; public ManualResetEvent eventX; public static int iCount = 0; public static int iMaxCount = 0; public Alpha(int MaxCount) { HashCount = new Hashtable(MaxCount); iMaxCount = MaxCount; } //线程池里的线程将调用Beta()方法 public void Beta(Object state) { //输出当前线程的hash编码值和Cookie的值 Console.WriteLine(" {0} {1} :", Thread.CurrentThread.GetHashCode(),((SomeState)state).Cookie); Console.WriteLine("HashCount.Count=={0}, Thread.CurrentThread.GetHashCode()=={1}", HashCount.Count, Thread.CurrentThread.GetHashCode()); lock (HashCount) { //如果当前的Hash表中没有当前线程的Hash值,则添加之 if (!HashCount.ContainsKey(Thread.CurrentThread.GetHashCode())) HashCount.Add (Thread.CurrentThread.GetHashCode(), 0); HashCount[Thread.CurrentThread.GetHashCode()] = ((int)HashCount[Thread.CurrentThread.GetHashCode()])+1; } int iX = 2000; Thread.Sleep(iX); //Interlocked.Increment()操作是一个原子操作,具体请看下面说明 Interlocked.Increment(ref iCount); if (iCount == iMaxCount) { Console.WriteLine(); Console.WriteLine("Setting eventX "); eventX.Set(); } } } public class SimplePool { public static int Main(string[] args) { Console.WriteLine("Thread Pool Sample:"); bool W2K = false; int MaxCount = 10;//允许线程池中运行最多10个线程 //新建ManualResetEvent对象并且初始化为无信号状态 ManualResetEvent eventX = new ManualResetEvent(false); Console.WriteLine("Queuing {0} items to Thread Pool", MaxCount); Alpha oAlpha = new Alpha(MaxCount); //创建工作项 //注意初始化oAlpha对象的eventX属性 oAlpha.eventX = eventX; Console.WriteLine("Queue to Thread Pool 0"); try { //将工作项装入线程池 //这里要用到Windows 2000以上版本才有的API,所以可能出现NotSupportException异常 ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta), new SomeState(0)); W2K = true; } catch (NotSupportedException) { Console.WriteLine("These API's may fail when called on a non-Windows 2000 system."); W2K = false; } if (W2K)//如果当前系统支持ThreadPool的方法. { for (int iItem=1;iItem < MaxCount;iItem++) { //插入队列元素 Console.WriteLine("Queue to Thread Pool {0}", iItem); ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta),new SomeState(iItem)); } Console.WriteLine("Waiting for Thread Pool to drain"); //等待事件的完成,即线程调用ManualResetEvent.Set()方法 eventX.WaitOne(Timeout.Infinite,true); //WaitOne()方法使调用它的线程等待直到eventX.Set()方法被调用 Console.WriteLine("Thread Pool has been drained (Event fired)"); Console.WriteLine(); Console.WriteLine("Load across threads"); foreach(object o in oAlpha.HashCount.Keys) Console.WriteLine("{0} {1}", o, oAlpha.HashCount[o]); } Console.ReadLine(); return 0; } } #endregion
3、
#region ThreadTest Three lock互斥锁 public class threst { public static object LockExample = new object(); static int i = 0; public static void MethodSubA() { do { lock (LockExample) { i++; Console.WriteLine("线程A开始,共享数据值i={0}", i); Thread.Sleep(100); Console.WriteLine("线程A结束,共享数据值i={0}", i); } } while (1 == 1); } public static void MethodSubB() { do { lock (LockExample) { i--; Console.WriteLine("线程B开始,共享数据值i={0}", i); Thread.Sleep(100); Console.WriteLine("线程B结束,共享数据值i={0}", i); } } while (1 == 1); } static void Main(string[] args) { Thread threadSubA = new Thread(new ThreadStart(MethodSubA)); Thread threadSubB = new Thread(new ThreadStart(MethodSubB)); Console.WriteLine("线程A启动..........."); threadSubA.Start(); Console.WriteLine("线程B启动..........."); threadSubB.Start(); do { if (Console.Read() == 'e') { threadSubA.Abort(); threadSubB.Abort(); break; } } while (1 == 1); } } #endregion
4、
#region ThreadTest Four Mutex互斥体 class Program { public static Mutex MSample; public static int i = 0; static void Main(string[] args) { MSample = new Mutex(false); Thread ThreadSubA = new Thread(new ThreadStart(new SubProgram().MethodSubA)); Thread ThreadSubB = new Thread(new ThreadStart(new SubProgram().MethodSubB)); Console.WriteLine("线程A启动.............."); ThreadSubA.Start(); Console.WriteLine("线程B启动.............."); ThreadSubB.Start(); do { if (Console.Read() == 'e') { ThreadSubA.Abort(); ThreadSubB.Abort(); break; } } while (1 == 1); } } class SubProgram { public void MethodSubA() { do { Program.MSample.WaitOne(); Program.i++; Console.WriteLine("线程A开始,共享数据值i={0}", Program.i); Thread.Sleep(10); Console.WriteLine("线程A结束,共享数据值i={0}", Program.i); Program.MSample.ReleaseMutex(); Thread.Sleep(10); } while (1 == 1); } public void MethodSubB() { do { Program.MSample.WaitOne(); Program.i--; Console.WriteLine("线程B开始,共享数据值i={0}", Program.i); Thread.Sleep(10); Console.WriteLine("线程B结束,共享数据值i={0}", Program.i); Program.MSample.ReleaseMutex(); Thread.Sleep(10); } while (1 == 1); } } #endregion
5-16、
#region ThreadTest Five class Program { private static object SObjectA = new object(); private static object SObjectB = new object(); public static void DemoA() { if (Monitor.TryEnter(SObjectA, 1000)) { try { Thread.Sleep(1000); if (Monitor.TryEnter(SObjectB, 2000)) Monitor.Exit(SObjectB); else Console.WriteLine("TryEnter SObjectB 超时......"); } catch { } finally { Monitor.Exit(SObjectA); } } Console.WriteLine("DemoA 执行完毕.........."); } public static void DemoB() { if (Monitor.TryEnter(SObjectB, 2000)) { try { Thread.Sleep(2000); if (Monitor.TryEnter(SObjectA, 1000)) Monitor.Exit(SObjectA); else Console.WriteLine("TryEnter SObjectB 超时......"); } catch { } finally { Monitor.Exit(SObjectB); } } Console.WriteLine("DemoB 执行完毕.........."); } static void Main(string[] args) { Thread ThreadOne = new Thread(DemoA); Thread ThreadTwo = new Thread(DemoB); ThreadOne.Start(); ThreadTwo.Start(); Thread.Sleep(10000); Console.WriteLine("线程结束....."); } } #endregion #region ThreadTest Six 线程池的使用 class Program { static void Main(string[] args) { for (int i = 0; i < 10; i++) { ThreadPool.QueueUserWorkItem(new WaitCallback(MethodA),i); } Console.ReadLine(); } static void MethodA(object Num) { int QueueNum = (int)Num; Console.WriteLine("线程号:{0}",QueueNum); Console.WriteLine(); } } #endregion #region ThreadTest Seven 多个参数,使用结构体传参 public struct StructRow { public int First; public int Second; } class Propram { static void Main(string[] args) { ClassDemo ClassOne = new ClassDemo(); StructRow rcM; rcM.First = 3; rcM.Second = 4; Thread ThreadOne = new Thread(new ParameterizedThreadStart(ClassOne.Demo)); ThreadOne.Start(rcM); Console.Read(); } } class ClassDemo { public void Demo(object rcMln) { StructRow rowCol = (StructRow)rcMln; for (int i = 0; i < rowCol.First; i++) { for (int j = 0; j < rowCol.Second; j++) { Console.WriteLine("内循环输出:{0}", j); } Console.WriteLine("外循环输出:{0}", i); Console.WriteLine("\n"); } } } #endregion #region ThreadTest Eight 创建专用线程异步执行操作 public static class Program { public static void Main() { Console.WriteLine("Main thread: starting a dedicated thread to do an asynchronous operation"); Thread dedicatedThread = new Thread(ComputeBoundOp); dedicatedThread.Start(5); Console.WriteLine("Main thread: Doing other work here"); Thread.Sleep(10000); dedicatedThread.Join();//等待线程终止 Console.WriteLine("Hit <Enter> to end this program..."); Console.ReadLine(); } private static void ComputeBoundOp(object state) { Console.WriteLine("In computeBoundOp: state={0}",state); Thread.Sleep(1000); } } #endregion #region ThreadTest Nine 前台线程和后台线程的区别 public static class Program { public static void Main() { Thread t = new Thread(Worker); t.IsBackground = true; t.Start(); //如果t是一个前台进程,则应用程序10秒后才终止 //如果t是一个后台进程,则应用程序立即终止 Console.WriteLine("Returning from Main"); } private static void Worker() { Thread.Sleep(10000); Console.WriteLine("Returning from Worker"); } } #endregion #region ThreadTest Ten 线程池以异步方式调用一个方法 public static class Program { public static void Main() { Console.WriteLine("Main thread: queuing an asynchronous operation"); ThreadPool.QueueUserWorkItem(ComputeBoundOp,5); Console.WriteLine("Main thread: Doing other work here"); Thread.Sleep(10000); Console.WriteLine("Hit <Enter> to end this program..."); Console.ReadLine(); } private static void ComputeBoundOp(object state) { Console.WriteLine("In computeBoundOp: state={0}", state); Thread.Sleep(1000); } } #endregion #region ThreadTeat Eleven 如何通过阻止执行上下文的流动来影响线程逻辑调用上下文中的数据 public class Program { public static void Main() { //将一些数据放到Main线程的逻辑调用上下文中 CallContext.LogicalSetData("Name","Jeffrey"); //线程池能访问逻辑调用上下文数据 ThreadPool.QueueUserWorkItem(state =>Console.WriteLine("Name={0}",CallContext.LogicalGetData("Name"))); //现在阻止Main线程的执行上下文的流动 ExecutionContext.SuppressFlow(); //线程池线程不能访问逻辑调用上下文数据 ThreadPool.QueueUserWorkItem(state=>Console.WriteLine("Name={0}",CallContext.LogicalGetData("Name"))); //恢复Main线程的执行上下文的流动 ExecutionContext.RestoreFlow(); } } #endregion #region ThreadTest Twelve CancellationTokenSource取消线程操作 .Net FrameWork 4.0 public class Propram { public static void Main() { CancellationTokenSource cts = new CancellationTokenSource(); ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));//禁止被取消CancellationToken.None Console.WriteLine("按 <Enter> 键终止操作"); Console.ReadLine(); cts.Cancel(); Console.ReadLine(); } private static void Count(CancellationToken token, int countTo) { for (int count = 0; count < countTo; count++) { if (token.IsCancellationRequested) { Console.WriteLine("Count 已经被取消"); token.Register(() => Console.WriteLine("Count 取消后调用了这个方法"), false); break; } Console.WriteLine(count); Thread.Sleep(200); } Console.WriteLine("Count 执行结束"); } } #endregion #region ThreadTest Thirteen Task 取消任务 public class Program { public static void Main() { CancellationTokenSource ctks = new CancellationTokenSource(); Task<Int32> t = new Task<Int32>(() => sum(ctks.Token, 10000), ctks.Token); t.Start(); ctks.Cancel();//t.Wait(); try { Console.WriteLine("The sum is: " + t.Result); } catch (AggregateException x) //AggregateException 封闭异常对象的一个集合 { x.Handle(e => e is OperationCanceledException); Console.WriteLine("Sum was canceled"); } Console.ReadLine(); } private static Int32 sum(CancellationToken ctk, Int32 n) { Int32 sum = 0; for (; n > 0; n--) { ctk.ThrowIfCancellationRequested(); checked { sum += n; } } return sum; } } #endregion #region ThreadTest Fourteen 一个任务完成时自动启动另一个任务 public class Program { public static void Main() { CancellationTokenSource ctks = new CancellationTokenSource(); Task<Int32> t = new Task<Int32>(() => sum(ctks.Token, 10000)); t.Start(); Task twk = t.ContinueWith(task => Console.WriteLine("The sum is: " + task.Result));//在任务 t 结束后执行任务 twk twk.ContinueWith(tsk=>Console.WriteLine("twk is completed with no Exception!"),TaskContinuationOptions.OnlyOnRanToCompletion);//在没有任何异常的情况下执行这句 Console.ReadLine(); } private static Int32 sum(CancellationToken ctk, Int32 n) { Int32 sum = 0; for (; n > 0; n--) { checked { sum += n; } } return sum; } } #endregion #region ThreadTest Fivteen 让任务支持父/子关系(任务可以启动子任务) public static class Propram { public static void Main() { Task<Int32[]> parent = new Task<Int32[]>(() => { var results = new Int32[3]; new Task(() => results[0] = Sum(1000), TaskCreationOptions.AttachedToParent).Start(); new Task(() => results[1] = Sum(2000), TaskCreationOptions.AttachedToParent).Start(); new Task(() => results[2] = Sum(3000), TaskCreationOptions.AttachedToParent).Start(); return results; } ); parent.ContinueWith(parentTask => Array.ForEach(parent.Result, Console.WriteLine)); parent.Start(); Console.ReadLine(); } private static Int32 Sum(Int32 n) { Int32 sum = 0; for (; n > 0; n--) { checked { sum += n; } } return sum; } } #endregion #region ThreadTest Sixteen 如何使用任务工厂 TaskFactory (没弄明白) public class Program { public static void Main() { Task parent = new Task(() => { var cts = new CancellationTokenSource(); var tf = new TaskFactory<Int32>(cts.Token, TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); /*这个任务创建并启动3个子任务*/ var childTasks = new[]{ tf.StartNew(()=>Sum(cts.Token,1000)), tf.StartNew(()=>Sum(cts.Token,2000)), tf.StartNew(()=>Sum(cts.Token,Int32.MaxValue))//太大,抛出异常 }; /*任务子任务抛出异常,就取消其余子任务*/ for (Int32 task = 0; task < childTasks.Length; task++) { childTasks[task].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted); } /*所有子任务完成后,从未出错/未取消的任务获取返回最大值,然后将最大值传给另一个任务来显示结果*/ tf.ContinueWhenAll(childTasks, completedTasks => completedTasks.Where(t => !t.Isfaulted && t.IsCanceled).Max(t => t.Result), CancellationToken.None).ContinueWith(t => Console.WriteLine("最大值是:" + t.Result), TaskContinuationOptions.ExecuteSynchronously); } ); /*子任务完成后,也显示任务未处理的异常*/ parent.ContinueWith(p => { /*我将所遇哦文本放到一个StringBuilder中,并值调用Console.WriteLine一次,*/ /*因为这个任务可能和上面的任务并行执行,而我不希望任务的输出变得不连续*/ StringBuilder sb = new StringBuilder("The following exception(s) occurred:" + Environment.NewLine); foreach (var e in p.Exception.Flatten().InnerExceptions) sb.AppendLine(" " + e.GetType().ToString()); Console.WriteLine(sb.ToString()); }, TaskContinuationOptions.OnlyOnFaulted); parent.Start(); Console.ReadLine(); } private static Int32 Sum(CancellationToken ctk, Int32 n) { Int32 sum = 0; for (; n > 0; n--) { checked { sum += n; } } return sum; } } #endregion