目录
什么是进程:
C#如何操作进程:
什么是线程:
解决的问题:
单线程的问题:
线程10个应用(创建,结束,终止,控制,跨线程访问,并发,线程池)
多线程的应用场景:
是windows系统中的一个基本概念,他包含着一个运行程序所需要的资源。进程之间是相对独立的,一个进程无法直接访问另一个进程的数据(除非利用分布式计算方式),一个进程运行的失败也不会影响其他进程的运行。windows系统是利用进程把工作划分为多个独立的区域,进程也可以理解为一个程序的基本边界。
//显示出本机所有线程的名称
Process[] ps=Process.GetProcesses();
foreach(Process p in ps)
{
console.writeLine(p.processName);
}
cosole.readkey();
//执行一个记事本进程
Process.Start("notepad.exe");
console.readkey();
进程是一个资源的拥有者,因而在进程的创建,撤销,和切换的过程中,系统必须为之付出较大的时空开销,限制了并发程度的进一步提高。
你的程序在做运算,如果用户想要拖动你程序的窗体,如果只有单线程的话,程序是没有办法同时做两件事情的。
解决方案:
在创建一个线程,就可以解决以上的问题,主线程负责拖动,子线程负责运算
private void BtnCount_Click(object serder,EventArgs e)
{
Thread myThread=new Thread(StartCount); //参数内部的实质是委托
myThread.Start(); //start是标记可运行状态,但不是真正的执行,真正执行是操作系统说了算
}
private void StartCount()
{
int a=0;
for(int i=0;i<1000000;i++)
{
a=i;
}
MessageBox.show(a.ToString());
}
1.那什么时候子线程开始执行?
Start()是标记可运行状态,但不是真正的执行,真正执行是操作系统说了算
2.那什么时候子线程什么时候结束?
在子线程中调用的那个方法运行结束子线程就结束了
3.那我们可以不等到子线程调用的那个方法运行结束就结束子线程么?
可以,但是非常暴力,容易抛异常,因为代码正在执行,就把它结束了
4.子线程和主线程他们真正的运行时间怎么控制?
用到Join()这个方法,让主线程等子线程执行完毕之后,在继续执行之后的代码。
例子:首先开启线程A,紧接着线程A调用了join()方法进入阻塞状态,那么线程必须等待线程A执行结束之后再往下执行,线程A执行完毕,线程B开启,进入睡眠,主线程执行,线程B睡眠结束,执行;
Thread myThread=new Thread(StartCount); //参数内部的实质是委托
myThread.Start();
myThread.Join(1000); //这个方法就是让主线程等这个子线程执行1秒,在这一秒内不管这个子线程执行完毕与否,都继续走主线程之后的代码
5.会不会出现父线程关闭了,子线程还在运行?
会,比如上面拖动窗体和计算的那个例子,如果你运算的时间过长,在你运算过程中,用户把你窗体关了,但是计算那个线程还在,最终还是会在你窗体在显示运算结果。如何避免呢?我们就运用到了后台线程,就可以避免这一问题,主窗体一关,其他线程全部关闭。
Thread myThread=new Thread(StartCount);
myThread.IsBackground=true; //设置为后台线程
myThread.Start();
6.之前线程执行都是不带参数的方法,那么线程可以执行带参数的方法么?
当然可以,看下图:
下面是该方法的参数列表
public delegate void ParameterizedThreadStart(object obj);
7.我们如何实现跨线程访问
首先我们现要知道什么是跨线程访问,下面代码中this.textBox1.Text=a.Tostring(); 就是跨线程访问。
private void BtnCount_Click(object serder,EventArgs e)
{
Thread myThread=new Thread(StartCount); //参数内部的实质是委托
myThread.Start(); //start是标记可运行状态,但不是真正的执行,真正执行是操作系统说了算
}
private void StartCount()
{
int a=0;
for(int i=0;i<1000000;i++)
{
a=i;
}
this.textBox1.Text=a.Tostring(); //跨线程访问,textbox框是由主线程创建的
}
1).最直接的,关闭跨线程检测,但是非常不好
2).Invoke方法(委托,去找创建textbox的线程,由创建textbox的线程来执行showtextboxvalue方法,)
private void BtnCount_Click(object serder,EventArgs e)
{
Thread myThread=new Thread(StartCount); //参数内部的实质是委托
myThread.Start(); //start是标记可运行状态,但不是真正的执行,真正执行是操作系统说了算
}
private void StartCount()
{
int a=0;
for(int i=0;i<1000000;i++)
{
a=i;
}
if(this.textBox1.InvokeRequired)//是否要对文本框进行跨线程访问
{
//<>泛型约束,约束一下调用的方法要有TextBox和string类型的参数
this.textBox1.Invoke(new Action(showTextBoxValue),this.textBox1,a.Tostring());
}
this.textBox1.Text=a.Tostring();
}
Private void ShowTextBoxValue(TextBox txt,string value)
{
}
8.如果两个线程同时用一个方法怎么办?
加锁
一个请求对应一个线程,页面一刷新就发一次请求,如果用户狂刷,狂发请求,怎么办?---线程池
9.为什么要有线程池?
线程池:提高了线程的利用率,非常适合工作任务非常小,而且又需要使用单独的线程来解决的问题。
10.什么时候用线程池,什么时候用手动创建线程?
1.我们向手动关闭线程的话那么必须手动创建
2.我们需要对线程池的线程的优先级做设置的情景下,只能使用手动创建线程(线程池里面取出来的都是normal,都是后台线程)
3.如果执行的线程执行时间特别长,建议手动创建线程
1.比如360要杀毒,但是你还要拖动你的窗体或者其他的操作
2.购物--生成订单(算订单,发邮件等等)到支付中间有很多工作,就可以用线程来处理其中的工作
3.希望获得更多操作系统资源尽快处理我们的业务,缩短处理时间
4.如果是一个非常复杂的操作。需要占用非常长的时间,而窗体又不允许阻塞UI线程