线程基础
线程和进程的区别?
进程就是一个应用程序实例的资源集合,每个进程中的资源是独立,一个进程崩溃不会影响另外一个进程。
每个进程默认都有一个主线程。通过主线程可以创建多个子线程,每个线程中的资源都是独立,但是每个线程都可以共享进程中的资源。
进程的启动和终止
//获取某个进程的信息 var process=Process.GetProcesses();//获取本地计算机的所有进程信息 var mypro=Process.GetProcessedByName("进程的名称")//获取指定的进程信息 //进程的启动 Process.Start("notepad"); //指定路径启动 Process.Start("c:\Demo.exe"); //需要携带额外的参数时 Process mypro=new Process(); mypro.StartInfo.FileName="文件名"; mypro.StartInfo.Arguments="参数"; mypro.Start(); //或者 Process p =new Process(); ProcessStartInfo ps= new ProcessStartInfo("notepad"); p.StartInfo=ps; p.Start();
线程基础
线程是进程中基本执行单位,一个进程中可以包含多个线程,进程中的资源是独有的 ,每个线程中的资源也是独有,但是多个线程可以共享进程中的资源。
线程的用途
1.让程序的用户界面保持可响应状态
2.同时处理多个请求
3.并行编程。
线程的滥用
线程既然在运行,肯定有代码,那么它一定会占用资源,也就是说线程是有开销成本的。
总之就是线程很复杂,并且线程不一定会加快你程序的运行速度,有时候甚至会减慢你整个程序的执行。
线程的创建
class Program{ static void Main(string[] args) { Thread first = new Thread(FirstThread); first.Start(); for(int i=0;i<50;i++) { Console.Write("x"); } Console.Read(): } static void FirstThread(){ for(int i=0;i<50;i++) { Console.Write("y"); } } }
从运行代码的结果可以得出以下几个结论:
1.2个线程的代码的执行顺序是随机的,无法预知的。
2.线程代码的执行就像一个人在走路一样,他总是走走停停,但是最终总会走到目的地。
线程的结束
终止线程:Abort()方法,该方法是尝试将线程进行销毁已达到终止线程的目的,在实际项目中一般使用CancellationToken
来终止线程。
线程的常用属性与方法
属性 | 说明 |
ManagedThreadId | 获取托管线程的Id,用来唯一区分一个线程,主要用在学习与调试线程时使用 |
Priority | 线程的优先级,在后面会详细讲解 |
ThreadState | 线程的状态,比如未启动,运行状态,阻塞状态等,在介绍线程的执行原理时会进一步讲解 |
IsBackground | 获取或设置此线程是否是一个后台线程 |
方法 | 说明 |
Sleep(毫秒) | 让线程休眠一段时间,也就是暂停线程代码的执行 |
Join() | 让调用此方法的线程处于阻塞状态 |
线程的优先级
线程类型可以通过其属性Priority来更改其优先级,此属性是一个ThreadPriority的枚举类型,其值有Lowest(最低),BelowNormal(低于正常级别),Normal(正常),AboveNormal(高于正常级别)
,Highest(最高),默认值为normal。
如果一个线程的优先级设为最高,也不一定表示此线程的代码总是会优先执行,还是要看具体情况。
//设置线程的优先级别 var thread =new Thread(BackDemo); thread.Priority=ThreadPriority.Normal;
线程的术语
主线程和辅助线程
辅助线程有时候也被称为工作线程,工作线程是在主线程中创建出来的,工作线程结束了并不会导致整个程序的结束,但是如果主线程结束了,那么整个程序也就结束了。
前台线程和后台线程
前台线程会导致程序都处于存活的状态,而后台线程不会,一旦所有的前台线程都执行完毕,那么会导致程序的关闭,即便这个时候还有后台线程没有执行完毕也会导致程序的关闭。
//设为后台线程 var thread = new Thread(Demo); thread.IsBackground=true;
线程的数据传输
Thread对象的构造函数结构:
public delegate void ThreadStart(); public delegate void ParameterizedThreadStart(object obj);
Thread对象的实例化
//方式一 int max=100; Thread t =new Thread(PrintEvent); t.Start(max); static void PrintEvent(object obj) { int max=Convert.ToInt32(obj); Console.Write(max); }
//方式二 int max=100; Thread t = new Thread(delegate(object max){ int val=Convert.ToInt32(max); Console.Write(val); }); t.Start(max);
//方式三 int max =100; Thread t = new Thread(val=>{ int max=Convert.ToInt32(val); Console.Write(max); });
在循环中创建线程并输出
for(int i=0;i<10;i++){ int temp=i; new Thread(()=>{ Console.WriteLine(temp); }).Start(); }
解决了输出相同的数字。由于之前引用的都是一个同一个i,所有才会导致这样的情况发发生
因此在循环中定义一个变量进行迭代,每个线程都会引用不同的变量,虽然他们的名字相同。
定义个类进行数据的传输
class Calc { public int OperationOne{get;set;} public int OperationTwo{get;set} public void DoCal() { Console.WriteLine("result is {0}",OperationOne+OperationTwo); } } static void Main(string[] args) { Calc c= new Calc() {OperationOne=5,OperationTwo=10} ; Thread t=new Thread(c.DoCal); t.Start(); Console.ReadKey(); }
接收线程的结果
class CalcEx { Thread t; int result; public int OperationOne{get;set;} public int OperationTwo{get;set;} public void DoCal(){ t=new Thread(()=>{ result=OperationOne+OpenrationTwo; }); t.Start(); } public int Result{ get{ if(t.ThreadState!=ThreadState.Stopped) t.Join(); return result; } } }
线程的执行原理
时间片
线程并不是顺序的执行的,每创建一个线程大约需要消耗1M的内存,执行程序指令的是CPC。
时间片就是操作系统会分配给每个正在运行的进程一段CPU时间,现代操作系统允许同时运行多个进程,。
但是一个计算机通常只有一个CPU,它又不可能真正地同时运行多个任务,所以它看起来像同时运行,实际上是轮番运行,由于时间片很短,用户不会感觉到;
上下文切换
当一个线程的时间片用完的时候就会重新处于就绪状态让给其他线程使用,这个过程就属于一次上下文切换。
线程的状态与声明周期
通过ThreadState属性来得到当前线程的状态,ThreadState属性的返回值类型是一个ThreadState枚举。
主要的有:Unstarted(未启动)状态,Running(运行状态),Stopped(停止状态),WaitSleepJoin(等待状态).