在具有一个处理器的计算机上,多个线程可以利用用户事件之间很小的时间段在后台处理数据来达到丰富多彩的用户体验效果(快速的用户反应)。应用程序可通过使用多个线程技术完成这些任务:①通过网络进行通信;②执行占用长时间的操作;③区分具有不同优先级的任务;④使用户界面在执行后台任务时仍旧能快速响应用户交互。在多线程的进程中,除了主线程之外,还可以创建其他线程(辅助线程),其他线程可以与主线程一起并行执行。辅助线程用于执行耗时的任务或者时间要求紧迫的任务(主线程保持运行,后台线程做它的后台工作。对于Windows窗体程序来说,如果主线程试图执行冗长的工作,键盘和鼠标的操作将会变得迟钝,程序也会失去响应,此时使用多线程是十分合适的)。实际上,当执行需要较长时间才能完成的连续操作时,或者等待网络或其他的I/O设备响应时,都可以使用多线程技术。
进程:当一个程序开始运行时,它就是一个进程(或者说一个进程就是一段正在运行的程序实例)。进程包括:运行中的程序、程序所使用到的内存与系统资源(进程=进程标识+程序的文件名+运行的起始时间+(1个)虚拟的内存空间;其他的进程不能访问此内存空间)。一个进程可由一个或者多个线程组成,即有→进程:线程=1:m。
线程:程序中的一个执行流(操作系统分配CPU时间的基本单位)。每个线程都有自己的专有寄存器(栈指针、程序计数器等),但是代码区是共享的,即不同的线程可以执行同样的函数。线程被线程协调程序管理着,它是CLR委托给操作系统的函数。线程协调程序确保将所有活动的线程被分配适当的执行时间,并且那些等待或者阻止的线程都是不消耗CPU时间的。当线程由于外部因素(比如时间片)被中断称为“被抢占”,在大多数情况下,一个线程方面在被抢占的那一时那一刻就失去了对它的控制权。
属于同一个应用程序的所有线程逻辑上被包含在一个进程中。进程是指一个应用程序所运行的操作系统单元。进程与线程有某些相似的地方:比如说进程通常以时间片方式运行,线程也是类似的。二者关键上的区别:进程之间彼此完全隔绝的;线程与运行在相同程序的其他线程共享内存(堆heap)。这也是为什么线程如此有用:一个线程可以在后台读取数据,而另一个线程展示已经读取的数据。一个线程或是前台线程或是后台线程;后台线程与前台线程类似,区别是:后台线程不会防止进程终止!属于某个进程的所有前台线程都终止后,公共语言运行库就会结束该进程,同时属于该进程的所有后台线程都会立即停止,无论后台工作是否完成。
PS:在运行库控制下执行的代码叫做托管代码。相反,在运行库外运行的代码称为非托管代码。COM组件、ActiveX接口、Win32API函数都是非托管代码示例;使用new运算符实例化队象,就自动成为托管代码。使用c#编写托管代码,主要的优点就是:完全面向对象设计、使用委托取代函数指针增强了类型安全、自动垃圾回收减轻了编程负担。
(1)启动终止线程:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
////以下显示了主线程、辅助线程并发执行///
private volatile bool threadStopped;//多线程共访字段(控制线程终止)
//窗体load事件,无需触发便执行
private void Form1_Load(object sender, EventArgs e)
{
Thread t = new Thread(ThreadMethod);//创建线程实例(委托调用线程方法ThreadMethod)
t.IsBackground = true;//后台线程
t.Name = "我的辅助线程";//线程名
threadStopped = false;//共访字段为false时,可进入while循环执行线程工作
t.Start();//启动线程
Thread.Sleep(3000);//主线程暂停
MessageBox.Show("主线程");
threadStopped = true;
}
private void ThreadMethod()
{
int num = 0;
MessageBox.Show("辅助线程开始!");
while(!threadStopped)
{
//执行线程工作
//………………
num++;
//执行线程工作
Thread.Sleep(10);//一个线程挂起后,CPU就会调度其他线程(挂起线程时间片中剩余部分将让与另一线程)
}
MessageBox.Show("辅助线程结束!");//退出while循环,结束线程(线程方法结束,线程随之销毁)
//MessageBox.Show(num.ToString());
}
}
(2)在一个线程中访问另一个线程的控件:
①同一项目中添加的线程方法项
class MyClass
{
public volatile bool shouldStop;//多个并发线程共访变量
private Form1 m_form1;
public MyClass(Form1 form1)
{
m_form1 = form1;
}
public void ThreadMethod(object obj)//线程方法(实例化线程时作为参数)
{
string str = obj as string;//等价于(string)obj;
m_form1.ShowMessage(Thread.CurrentThread.Name+"Is Running!");
while (!shouldStop)
{
m_form1.ShowMessage(str);//线程执行的工作
Thread.Sleep(1000);//睡眠到期后,自动再执行
}
m_form1.ShowMessage(Thread.CurrentThread.Name+"Is Stopped!");//跳出循环,结束线程
}
}
②主体程序:
public partial class Form1 : Form
{
MyClass class1;
MyClass class2;
public Form1()
{
InitializeComponent();
class1 = new MyClass(this);
class2 = new MyClass(this);
}
//线程1启动按钮
private void button1_Click(object sender, EventArgs e)
{
class1.shouldStop = false;
Thread t1 = new Thread(class1.ThreadMethod);
t1.Name = "Thread1";
t1.IsBackground = true;
t1.Start("线程1");
}
//线程2启动按钮
private void button2_Click(object sender, EventArgs e)
{
class2.shouldStop = false;
Thread t2 = new Thread(class2.ThreadMethod);
t2.Name = "Thread2";
t2.IsBackground = true;
t2.Start("线程2");
}
//线程1终止按钮
private void button3_Click(object sender, EventArgs e)
{
class1.shouldStop = true;
}
//线程2终止按钮
private void button4_Click(object sender, EventArgs e)
{
class2.shouldStop = true;
}
//委托定义(类型)
delegate void ShowMessageDelegate(string message);
//按照委托定义的方法
public void ShowMessage(string message)
{
if(richTextBox1.InvokeRequired)//此处判断此线程为非控件绑定线程
{
ShowMessageDelegate d = ShowMessage;//方法绑定到委托对象
richTextBox1.Invoke(d, message);
}
else//此处判断此线程为控件绑定线程
{
richTextBox1.AppendText(message);
}
}
}
③结果:
![结果](https://img-blog.csdn.net/20170526115719275?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQ194eHk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(3)线程同步:
①程序代码:
public partial class Form1 : Form
{
public volatile bool shouldStop;//多个并发线程都可访问的字段【volatile易变的、不稳定的】
Thread t1;//定义线程1、2
Thread t2;
double total;//两个线程执行总数
private object thisLock;//lock锁定参数(实现线程同步)
public Form1()//构造函数【初始化】
{
InitializeComponent();
thisLock = new object();
}
//线程方法ThreadMethod
private void ThreadMethod()
{
double num = 0;//单个线程执行次数
while(!shouldStop)
{
num++;
lock(thisLock)//lock锁定实现同步:多个线程之间存在先后执行顺序的关联关系
{
total++;//lock锁定的临界区(代码不宜过多),【能确保仅有一个线程位于此区域,实现同步】
}
Thread.Sleep(2);//2为暂停时间间隔(暂停的意思就是:过了此时间后会继续执行!)
}
ShowMessage("线程" + Thread.CurrentThread.Name + "执行了" + num + "次");
}
private delegate void ShowMessageDelegate(string message);//委托类型(外观像抽象方法)
//按委托定义的方法(将在if{}中绑定于委托对象),其功能是在richTextBox输入内容(顾及非此控件绑定的线程情况下)
private void ShowMessage(string message)
{
if(richTextBox1.InvokeRequired)//为true,访问的线程不是控件绑定的线程
{
ShowMessageDelegate d = ShowMessage;
richTextBox1.Invoke(d, message);
}
else//为false,访问的线程是控件绑定的线程
{
richTextBox1.AppendText(message+"\n\r");
}
}
//线程启动按钮
private void button1_Click(object sender, EventArgs e)
{
shouldStop = false;
total = 0;
t1 = new Thread(ThreadMethod);//创建线程实例【Unstarted状态】(它将委托执行线程方法)
t1.Name = "线程1";//线程名
t1.IsBackground = true;//后台线程
t2 = new Thread(ThreadMethod);
t2.Name = "线程2";
t2.IsBackground = true;
t1.Start();//创建(启动)线程【Running状态】
t2.Start();
}
//线程终止按钮
private void button2_Click(object sender, EventArgs e)
{
shouldStop = true;//当shouldStop为true时,线程方法中ThreadMethod“跳过while{}”
ShowMessage("两个线程共执行:" + total + "次");
}
}
②;程序结果:
![结果](https://img-blog.csdn.net/20170526120003987?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQ194eHk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
以上参考宋付保等.《C#4.0》程序设计。