线程和进程

进程:进程包含一个程序运行所需要的资源,进程即是一个程序,一个进程可以有多个线程。

线程:操作系统能够进行运算调度的最小单位。

c多线程编程实例:C多线程(1)

Windows 任务管理器

进程可以有多个线程。

生命周期

UnStarted 处于创建但未启动状态

Runnable 调用了start,处于可运行或准备运行状态

Running 运行中状态

Not Runable 非运行状态,调用了sleep、wait或I/O被阻塞

Dead 任务完成后,处于死亡或终止状态

Thread

Thread 常用属性

class Program { static void Main(string[] args) { Console.WriteLine("主线程:" Thread.CurrentThread.ManagedThreadId); Thread t = new Thread(new ThreadStart(Thread_A)); Console.WriteLine("创建线程 -- 线程状态:" t.ThreadState); t.Start(); Thread.Sleep(1000); // 睡眠1秒 Console.ReadKey(); } private static void Thread_A() { Console.WriteLine("常用属性值:"); Console.WriteLine("当前运行线程实例:" Thread.CurrentThread); Console.WriteLine("当前线程唯一ID:" Thread.CurrentThread.ManagedThreadId); Console.WriteLine("当前线程名称:" Thread.CurrentThread.Name); Console.WriteLine("当前线程优先级:" Thread.CurrentThread.Priority); Console.WriteLine("当前线程状态:" Thread.CurrentThread.ThreadState); Console.WriteLine("当前线程是否处于活跃:" Thread.CurrentThread.IsAlive); Console.WriteLine("当前线程是否为后台线程:" Thread.CurrentThread.IsBackground); /* 前台线程:主程序必须等待线程执行完毕后才能退出程序 后台线程:主程序执行完毕后就退出,不管线程是否完成 */ } }

c多线程编程实例:C多线程(2)

输出

Thread 优先级

class Program { static void Main(string[] args) { Thread t1 = new Thread(new ThreadStart(A)); t1.Start(); Thread t2 = new Thread(new ThreadStart(B)); t2.Start(); Thread t3 = new Thread(new ThreadStart(C)); t3.Start(); Console.ReadKey(); } private static void A() { Console.WriteLine("A"); } private static void B() { Console.WriteLine("B"); } private static void C() { Console.WriteLine("C"); } }

第一次输出:ABC

第二次输出:BAC

第三次输出:ABC

第四次输出:ACB

c多线程编程实例:C多线程(3)

第四次输出

Thread 优先级相同时没有先后顺序,设置优先级:

class Program { static void Main(string[] args) { Thread t1 = new Thread(new ThreadStart(A)); t1.Start(); t1.Priority = ThreadPriority.Highest; Thread t2 = new Thread(new ThreadStart(B)); t2.Start(); t2.Priority = ThreadPriority.Highest; Thread t3 = new Thread(new ThreadStart(C)); t3.Start(); t3.Priority = ThreadPriority.Highest; Thread t4 = new Thread(new ThreadStart(D)); t4.Start(); Console.ReadKey(); } private static void A() { Console.WriteLine("A"); } private static void B() { Console.WriteLine("B"); } private static void C() { Console.WriteLine("C"); } private static void D() { Console.WriteLine("D"); } }

第一次输出:CABD

第二次输出:ABCD

第三次输出:ACBD

第四次输出:ACBD

D的优先级最低,ABC优先级都是 Highest,同优先级不分顺序

带参 Thread

class Program { static void Main(string[] args) { Console.WriteLine("Main,标识:" Thread.CurrentThread.ManagedThreadId); Thread t1 = new Thread(new ParameterizedThreadStart(A)); // 带参数的方法 t1.Start("ThreadTest"); // 传参 Console.WriteLine("Main,标识:" Thread.CurrentThread.ManagedThreadId); Console.ReadLine(); } private static void A(object data) { Console.WriteLine("Message: " data ",标识:" Thread.CurrentThread.ManagedThreadId); } }

c多线程编程实例:C多线程(4)

输出

Thread 线程阻塞

Thread.Join() 可以阻塞主线程

class Program { static void Main(string[] args) { Thread t1 = new Thread(() => { Console.WriteLine("A"); }); t1.Start(); t1.Join(); Console.WriteLine("主线程"); Console.Read(); } }

c多线程编程实例:C多线程(5)

输出

阻塞所有线程,t1 执行完成之后再执行其他线程

Thread.Sleep(); 阻塞当前线程

class Program { static void Main(string[] args) { Thread t1 = new Thread(() => { Console.WriteLine("A"); Thread.Sleep(1000); }); t1.Start(); Console.WriteLine("主线程"); Console.Read(); } }

c多线程编程实例:C多线程(6)

输出

当前线程阻塞1s,Thread.Sleep() 单位是ms

Thread 方法

c多线程编程实例:C多线程(7)

来源:https://www.lidihuo.com/csharp/csharp-thread-class.html

Lock 线程锁

例:A、B同时在银行取钱,余额只有1000,两人都需要取1000,A取出来1000后,B取得时候提示余额不足

class Program { private static object obj = new object(); private static int money = 1000; static void Main(string[] args) { Thread thread1 = new Thread(Sum1); thread1.Start(); Thread thread2 = new Thread(Sum1); thread2.Start(); Console.ReadKey(); } public static void Sum1() { lock (obj) { if(money >= 1000) { money -= 1000; Console.WriteLine("余额:{0}",money); } else { Console.WriteLine("余额不足"); } } } }

c多线程编程实例:C多线程(8)

输出

ThreadPool

ThreadPool 线程池是为了方便对线程进行管理,线程池可以限制线程数量且可以重复使用

static void Main(string[] args) { Console.WriteLine("Main,标识:" Thread.CurrentThread.ManagedThreadId); ThreadPool.QueueUserWorkItem(p => A("")); // A括号里面传参数 ThreadPool.QueueUserWorkItem(new WaitCallback(A)); Console.WriteLine("Main,标识:" Thread.CurrentThread.ManagedThreadId); Console.ReadLine(); } private static void A(object data) { Console.WriteLine("Message: " data ",标识:" Thread.CurrentThread.ManagedThreadId); }

c多线程编程实例:C多线程(9)

输出

class Program { static void Main(string[] args) { Console.WriteLine("Main,标识:" Thread.CurrentThread.ManagedThreadId); Thread t1 = new Thread(new ThreadStart(A)); Thread t2 = new Thread(new ThreadStart(B)); t1.Start(); t2.Start(); Console.WriteLine("Main,标识:" Thread.CurrentThread.ManagedThreadId); Console.ReadLine(); } private static void B() { Console.WriteLine("Thread B"); } private static void A() { Console.WriteLine("Thread A"); } }

c多线程编程实例:C多线程(10)

输出

两端代码运行过多次,Thread 主线程会等待线程,ThreadPool 主线程不会等待线程

ThreadPool 线程重用、线程数量

线程数量

class Program { static void Main(string[] args) { int workerThreads; // 工作线程 int completionPortThreads; // I/O 线程 ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads); Console.WriteLine($"最大线程数:{workerThreads},{completionPortThreads}"); ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads); Console.WriteLine($"最小线程数:{workerThreads},{completionPortThreads}"); Console.ReadLine(); } }

c多线程编程实例:C多线程(11)

输出

设置数量

class Program { static void Main(string[] args) { int workerThreads; // 工作线程 int completionPortThreads; // I/O 线程 // 设置最大线程 ThreadPool.SetMaxThreads(5, 5); // 设置最小线程 ThreadPool.SetMinThreads(1, 1); ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads); Console.WriteLine($"最大线程数:{workerThreads},{completionPortThreads}"); ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads); Console.WriteLine($"最小线程数:{workerThreads},{completionPortThreads}"); Console.ReadLine(); } }

c多线程编程实例:C多线程(12)

输出

线程重用

class Program { static void Main(string[] args) { ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney)); ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney)); ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney)); ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney)); ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney)); ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney)); ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney)); ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney)); Console.ReadKey(); } private static void GetMoney(object state) { Console.WriteLine("线程标识: " Thread.CurrentThread.ManagedThreadId); } }

c多线程编程实例:C多线程(13)

输出

从输出的线程标识中可以看出只用了三个线程,减少了线程的创建

带参 ThreadPool

class Program { static void Main(string[] args) { string msg = "The User Does't exit"; object mg = "Hello Banananana"; ThreadPool.QueueUserWorkItem((a) => Message(msg)); ThreadPool.QueueUserWorkItem(new WaitCallback(Message), mg); // 传参类型需要 Object Console.Read(); } private static void Message(string msg) { Console.WriteLine(msg); } private static void Message(object msg) { Console.WriteLine(msg ""); } }

c多线程编程实例:C多线程(14)

输出

c多线程编程实例:C多线程(15)

QueueUserWorkItem

c多线程编程实例:C多线程(16)

回调方法

Task

ThreadPool 不能控制线程执行的顺序,也不能获取线程池内线程的取消、异常、完成的通知

Task 无返回值线程

class Program { static void Main(string[] args) { Console.WriteLine("开始执行"); var factory = new TaskFactory(); Task t1 = factory.StartNew(() => Console.WriteLine("A,标识: {0}",Thread.CurrentThread.ManagedThreadId)); Task t2 = Task.Factory.StartNew(() => Console.WriteLine("B,标识: {0}",Thread.CurrentThread.ManagedThreadId)); Task t3 = new Task(() => Console.WriteLine("C,标识: {0}",Thread.CurrentThread.ManagedThreadId)); t3.Start(); Task t4 = Task.Run(() => Console.WriteLine("D,标识: {0}",Thread.CurrentThread.ManagedThreadId)); Console.Read(); } }

c多线程编程实例:C多线程(17)

输出

Task 有返回值线程

class Program { static void Main(string[] args) { Task<string> t1 = new Task<string>(() => { return $"A, 标识:{Thread.CurrentThread.ManagedThreadId}"; }); t1.Start(); Task<string> t2 = Task.Factory.StartNew(() => { return $"B, 标识:{Thread.CurrentThread.ManagedThreadId}"; }); Task<string> t3 = Task.Run(() => { return $"C, 标识:{Thread.CurrentThread.ManagedThreadId}"; }); Console.WriteLine(t1.Result); Console.WriteLine(t2.Result); Console.WriteLine(t3.Result); Console.Read(); } }

c多线程编程实例:C多线程(18)

输出

注:Task.Result 返回结果时会阻塞线程

Task 同步执行

class Program { static void Main(string[] args) { Task t1 = new Task(() => Console.WriteLine("Task 线程")); t1.RunSynchronously(); // 同步方法 Console.WriteLine("主线程"); Console.Read(); } }

c多线程编程实例:C多线程(19)

输出

Task 线程阻塞

Thread 也有方法可以进行阻塞,但每次只能对一个线程进行阻塞,Task 可以有方法可以解决这个问题,task.Wait() 等待 task 执行完成,类似 Thread.Join(),Task.WaitAll() 执行完所有 task 再解除线程,Task.WaitAny() 只要有一个 task 执行完成就解除线程

Task.Wait

class Program { static void Main(string[] args) { Task t1 = new Task(() => { Console.WriteLine("A"); }); t1.Start(); t1.Wait(); Console.WriteLine("主线程"); Console.Read(); } }

c多线程编程实例:C多线程(20)

Task.Wait()

阻塞所有线程,等待当前执行完成

Task.WaitAll

class Program { static void Main(string[] args) { List<Task> list = new List<Task>(); Task t1 = Task.Run(() => Console.WriteLine("A")); Task t2 = Task.Run(() => Console.WriteLine("B")); Task t3 = Task.Run(() => Console.WriteLine("C")); Task t4 = Task.Run(() => Console.WriteLine("D")); list.Add(t1); list.Add(t2); list.Add(t3); list.Add(t4); Task.WaitAll(list.ToArray()); Console.WriteLine("主线程"); Console.Read(); } }

c多线程编程实例:C多线程(21)

Task.WaitAll

等待 Task线程组 完成

Task.WaitAny

class Program { static void Main(string[] args) { List<Task> list = new List<Task>(); Task t1 = Task.Run(() => Console.WriteLine("A")); Task t2 = Task.Run(() => Console.WriteLine("B")); Task t3 = Task.Run(() => Console.WriteLine("C")); Task t4 = Task.Run(() => Console.WriteLine("D")); list.Add(t1); list.Add(t2); list.Add(t3); list.Add(t4); Task.WaitAny(list.ToArray()); Console.WriteLine("主线程"); Console.Read(); } }

c多线程编程实例:C多线程(22)

Task.WaitAny

线程组任意线程完成就接触阻塞

Task 延续操作

有一个需求,需要在 task 线程组 执行完成之后执行

class Program { static void Main(string[] args) { List<Task> list = new List<Task>(); Task t1 = Task.Run(() => Console.WriteLine("A")); Task t2 = Task.Run(() => Console.WriteLine("B")); Task t3 = Task.Run(() => Console.WriteLine("C")); Task t4 = Task.Run(() => Console.WriteLine("D")); list.Add(t1); list.Add(t2); list.Add(t3); list.Add(t4); // 二选一即可 Task.WhenAll(list.ToArray()).ContinueWith(t => Console.WriteLine("执行完成")); // Task.Factory.ContinueWhenAll(list.ToArray(), t => Console.WriteLine("执行完成")); Console.WriteLine("主线程"); Console.Read(); } }

c多线程编程实例:C多线程(23)

输出

从输出中可以看出,task 不会阻塞主线程

有一个需求,需要在 task 线程任意线程执行完成之后执行

class Program { static void Main(string[] args) { List<Task> list = new List<Task>(); Task t1 = Task.Run(() => Console.WriteLine("A")); Task t2 = Task.Run(() => Console.WriteLine("B")); Task t3 = Task.Run(() => Console.WriteLine("C")); Task t4 = Task.Run(() => Console.WriteLine("D")); list.Add(t1); list.Add(t2); list.Add(t3); list.Add(t4); // 二选一即可 Task.WhenAny(list.ToArray()).ContinueWith(t => Console.WriteLine("执行完成")); // Task.Factory.ContinueWhenAny(list.ToArray(), t => Console.WriteLine("执行完成")); Console.WriteLine("主线程"); Console.Read(); } }

c多线程编程实例:C多线程(24)

输出

这个方法也不会阻塞主线程

Task 任务取消

有一个下载任务已运行,但这个文件已经不需要了,需要取消这个下载任务

class Program { static void Main(string[] args) { var cts = new CancellationTokenSource(); int i; Task t1 = new Task(() => { i = 0; while (!cts.IsCancellationRequested) { Thread.Sleep(1000); Console.WriteLine($"下载中:{i }%"); if(cts.IsCancellationRequested) Console.WriteLine("下载已取消"); } }); t1.Start(); // cts.Cancel(); // 立刻取消 cts.CancelAfter(1000 * 10); // 10秒后取消 Console.Read(); } }

c多线程编程实例:C多线程(25)

输出

除了使用 if 语句输出 下载已取消,CancellationTokenSource 也有一个自带的注册任务取消事件

class Program { static void Main(string[] args) { var cts = new CancellationTokenSource(); int i; Task t1 = new Task(() => { i = 0; while (!cts.IsCancellationRequested) { Thread.Sleep(1000); Console.WriteLine($"下载中:{i }%"); } }); // 取消后执行 cts.Token.Register(() => { Console.WriteLine("下载已取消"); }); t1.Start(); cts.CancelAfter(1000 * 10); Console.Read(); } }

c多线程编程实例:C多线程(26)

输出

异步方法(async/await)

class Program { static void Main(string[] args) { Console.WriteLine(GetContentAsync().Result); Console.Read(); } // 不会阻塞线程 async static Task<string> GetContentAsync() { Encoding GB2312 = Encoding.GetEncoding("GB2312"); Encoding GBK = Encoding.GetEncoding("GBK"); FileStream fs = new FileStream(@"D:\1.txt", FileMode.Open); byte[] bytes = new byte[fs.Length]; Console.WriteLine("开始读取文件"); int len = await fs.ReadAsync(bytes,0,bytes.Length); string res = Encoding.UTF8.GetString(bytes); return res; } }

c多线程编程实例:C多线程(27)

输出

Task 对ThreadPool做了封装,主要是为了更好地控制线程池中的线程

完!坚持and放弃,我选择坚持

,