进程:程序开始运行时,它便是一个进程;进程包括运行中的程序和程序所使用到的内存和系统资源;一个进程至少有一个主线程。
线程:线程是程序中的一个执行流,每个线程都有自己的寄存器(栈指针、程序计数器等),但代码区是共享的。即不同的线程可以执行同样的函数。
多线程:是指程序中包含多个执行流;即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说,允许单个程序创建多个并行执行的线程来完成各自的任务。
多线程的好处:提高CPU的利用率。在多线程的程序中,一个线程必须等待的时候,CPU可以继续运行其他线程而不是等待,从而大大提高程序的效率。
多线程的不利之处:
- 线程也是程序,所有线程需要占用内容,线程越多占用内存越多。
- 多线程需要协调和管理,所以CPU需要花时间来跟踪线程。
- 线程之间对共享资源的访问会相互影响,必须解决竞用共享资源问题。
- 线程太多会导致控制太复杂,最终可能导致太多BUG。
通过 Thread 类的静态属性 CurrentThread 可以获取当前正在执行的线程。
不管创建了多少个这个类的实例,但是类的静态属性在内存中只有一个。
很容易理解 CurrentThread 为什么是静态的--虽然有多个线程同时存在,但是在某一个时刻,CPU 只能执行其中一个!
所有与多线程机制应用相关的类都是放在System.Threading命名空间中。
Thread有几个至关重要的方法:
- Start( ) -- 启用线程;该方法只是通知CPU此线程可以被执行,但具体执行时机则由CPU自行决定。
- Sleep(int) -- 静态方法,暂停当前线程指定的毫秒数
- Abort( ) -- 通常使用该方法终止一个线程
- Suspent( ) -- 该方法并不终止未完成的线程,仅仅是挂起线程,后期还可以恢复
- Resume( ) -- 恢复Suspent( )方法挂起线程的执行
当线程之间争夺CPU时,CPU按照线程的优先级给予服务。
在C#应用程序中,存在5个不同优先级,由高至低分别是
- Highest
- AboveNormal
- Normal
- BelowNormal
- Lowest
系统默认优先级是TheradPriority.Normal ;通过设定线程优先级,可以合理的安排相对重要的线程优先执行,例如用户的响应等等。
线程的调度算法非常复杂。记住,优先级高的线程并不一定先执行,但 CPU 会将更多的时间片分给优先级高的线程,因此,在相同任务量的前提下,高优先级线程将会较快的完成任务。
Winform 中多线程的应用
在 Winform 程序总,一般称绘制窗体和响应用户的线程为主线程,或 UI 线程。单线程最显著的缺点是,当一个事件发生,程序进行一个耗时的运算动作时,UI 线程会出现假死现象,此时会无视对用户的响应。
下面的代码会模拟一些不同的情况:
1 void DoSomething() 2 { 3 for (int i = 0; i < 900000000; i++) 4 { 5 6 } 7 MessageBox.Show("It's finished."); 8 } 9 10 void ShowStr(object obj) 11 { 12 var list = obj as List<string>; 13 if (list != null) 14 { 15 foreach (var item in list) 16 { 17 MessageBox.Show(item.ToString()); 18 } 19 } 20 else 21 MessageBox.Show("null"); 22 } 23 24 // UI 单线程,运行时窗体会卡死一段时间 25 private void btnUI_Click(object sender, EventArgs e) 26 { 27 DoSomething(); 28 } 29 30 // 调用无參函数,此时窗体能响应用户 31 private void btnThreadA_Click(object sender, EventArgs e) 32 { 33 Thread thread = new Thread(DoSomething); 34 thread.Start(); 35 } 36 37 // 当所有前台线程都关闭时,后台线程将立即结束运行,无条件的关闭 38 // 而前台线程运行时,即使关闭 Form 主程序,该线程仍将继续运行,直到计算完毕 39 private void btnThreadB_Click(object sender, EventArgs e) 40 { 41 Thread thread = new Thread(DoSomething); 42 thread.IsBackground = true; 43 thread.Start(); 44 } 45 46 // 调用有参函数 47 private void btnThreadC_Click(object sender, EventArgs e) 48 { 49 Thread thread = new Thread(ShowStr); 50 thread.Start(new List<string> { "Jacky", "Skysoot", "Sam" }); 51 }
Thread 类的 4 个构造函数基本分为 2 类,有参和无參。而 ParameterizedThreadStart 委托定义的方法原型的参数为 Object 类型,这提高了传参最大的灵活性。当然,在被调用的函数内部,需要依据一定的约定将 Object 对象进行转型处理。