多线程在构建大型系统的时候是需要重点关注的一个重要方面
特别是在效率(系统跑得多快?)和性能(系统工作正常?)之间做一个权衡的时候
恰当的使用多线程可以极大的提高系统性能
什么是线程?
每个正在系统上运行的程序都是一个进程每个进程包含一到多个线程进程也可能是整个程序或者是部分程序的动态执行线程是一组指令的集合或者是程序的特殊段它可以在程序里独立执行也可以把它理解为代码运行的上下文所以线程基本上是轻量级的进程它负责在单个程序里执行多任务通常由操作系统负责多个线程的调度和执行
什么是多线程?
多线程是为了使得多个线程并行的工作以完成多项任务以提高系统的效率线程是在同一时间需要完成多项任务的时候被实现的
使用线程的好处有以下几点
·使用线程可以把占据长时间的程序中的任务放到后台去处理
·用户界面可以更加吸引人这样比如用户点击了一个按钮去触发某些事件的处理可以弹出一个进度条来显示处理的进度
·程序的运行速度可能加快
·在一些等待的任务实现上如用户输入文件读写和网络收发数据等线程就比较有用了在这种情况下我们可以释放一些珍贵的资源如内存占用等等
还有其他很多使用多线程的好处这里就不一一说明了
一些线程模型的背景
我们可以重点讨论一下在Win环境中常用的一些模型
·单线程模型
在这种线程模型中一个进程中只能有一个线程剩下的进程必须等待当前的线程执行完这种模型的缺点在于系统完成一个很小的任务都必须占用很长的时间
·块线程模型(单线程多块模型STA)
这种模型里一个程序里可能会包含多个执行的线程在这里每个线程被分为进程里一个单独的块每个进程可以含有多个块可以共享多个块中的数据程序规定了每个块中线程的执行时间所有的请求通过Windows消息队列进行串行化这样保证了每个时刻只能访问一个块因而只有一个单独的进程可以在某一个时刻得到执行这种模型比单线程模型的好处在于可以响应同一时刻的多个用户请求的任务而不只是单个用户请求但它的性能还不是很好因为它使用了串行化的线程模型任务是一个接一个得到执行的
·多线程块模型(自由线程块模型)
多线程块模型( MTA )在每个进程里只有一个块而不是多个块这单个块控制着多个线程而不是单个线程这里不需要消息队列因为所有的线程都是相同的块的一个部分并且可以共享这样的程序比单线程模型和STA的执行速度都要块因为降低了系统的负载因而可以优化来减少系统idle的时间这些应用程序一般比较复杂因为程序员必须提供线程同步以保证线程不会并发的请求相同的资源因而导致竞争情况的发生这里有必要提供一个锁机制但是这样也许会导致系统死锁的发生
多线程在NET里如何工作?
在本质上和结构来说NET是一个多线程的环境有两种主要的多线程方法是NET所提倡的使用ThreadStart来开始你自己的进程直接的(使用ThreadPoolQueueUserWorkItem)或者间接的(比如StreamBeginRead或者调用BeginInvoke)使用ThreadPool类一般来说你可以手动为长时间运行的任务创建一个新的线程另外对于短时间运行的任务尤其是经常需要开始的那些进程池是一个非常好的选择进程池可以同时运行多个任务还可以使用框架类对于资源紧缺需要进行同步的情况来说它可以限制某一时刻只允许一个线程访问资源这种情况可以视为给线程实现了锁机制线程的基类是SystemThreading所有线程通过CLI来进行管理
·创建线程
创建一个新的Thread对象的实例Thread的构造函数接受一个参数
Thread DummyThread = new Thread( new ThreadStart(dummyFunction) );
·执行线程
使用Threading命名空间里的start方法来运行线程
DummyThreadStart ();
·组合线程
经常会出现需要组合多个线程的情况就是当某个线程需要其他线程的结束来完成自己的任务假设DummyThread必须等待DummyPriorityThread来完成自己的任务我们只需要这样做
DummyPriorityThreadJoin() ;
·暂停线程
使得线程暂停给定的秒
DummyPriorityThread Sleep (<Time in Second>);
·中止线程
如果需要中止线程可以使用如下的代码
DummyPriorityThreadAbort();
·同步
经常我们会遇到需要在线程间进行同步的情况下面的代码给出了一些方法
using System;using SystemThreading;namespace SynchronizationThreadsExample{
class SynchronizationThreadsExample{
private int counter = ;
static void Main( ) {
SynchronizationThreadsExample STE = new SynchronizationThreadsExample();
STEThreadFunction( );
}
public void ThreadFunction ( ) {
Thread DummyThread = new Thread( new ThreadStart(SomeFunction) ;
DummyThreadIsBackground=true;
DummyThreadName = First Thread;
DummyThreadStart( );
ConsoleWriteLine(Started thread {} DummyThreadName);
Thread DummyPriorityThread = new Thread( new ThreadStart(SomeFunction) );
DummyPriorityThreadIsBackground=true;
DummyPriorityThreadName = Second Thread;
DummyPriorityThreadStart( );
ConsoleWriteLine(Started thread {} DummyPriorityThreadName);
DummyThreadJoin( );
DummyPriorityThreadJoin( );
}
public void SomeFunction( ) {
try {
while (counter < ) {
int tempCounter = counter;
tempCounter ++;
ThreadSleep();
counter = tempCounter;
ConsoleWriteLine( Thread {} SomeFunction: {}ThreadCurrentThreadName counter);
}
}
catch (ThreadInterruptedException Ex) {
ConsoleWriteLine( Exception in thread {} ThreadCurrentThreadName);
}
finally {
ConsoleWriteLine( Thread {} Exiting ThreadCurrentThreadName);
}
}
}
}
·使用Interlock
C#提供了一个特殊的类叫做interlocked就是提供了锁机制的实现我们可以加入如下的代码实现锁机制
InterlockedSomeFunction (ref counter);
·使用锁
这是为了锁定代码关键区域以进行同步锁定代码如下
lock (this){ Some statements ;}
·使用 Monitor
当有需要进行线程管理的时候我们可以使用
MonitorEnter(this);
其他也有一些方法进行管理这里就不一一提及了
线程的缺点
线程自然也有缺点以下列出了一些
·如果有大量的线程会影响性能因为操作系统需要在他们之间切换
·更多的线程需要更多的内存空间
·线程会给程序带来更多的bug因此要小心使用
·线程的中止需要考虑其对程序运行的影响
·通常块模型数据是在多个线程间共享的需要一个合适的锁系统替换掉数据共享