日期:2010-03-04  浏览次数:20432 次

多线程是很多驾驭体系所具有的特性,它能大大提升程序的运行效率,因此多线程编程技艺为编程者遍及关切。眼前微软的.Net战略正进一步推进,各种相干的技艺正为盛大编程者所接纳,同样在.Net中多线程编程技艺具有相称首要的地位。本文我就向大众介绍在.Net下进行多线程编程的基本办法和程序。开始新线程在.Net下树立一个新线程长短常轻易的,你可以通过以下的语句来开始一个新的线程:Threadthread=newThread(newThreadStart(ThreadFunc));thread.Start();首先条语句树立一个新的Thread对象,并指明了一个该线程的办法。当新的线程开始时,该办法也就被调用执行了。该线程对象通过一个System..Threading.ThreadStart类的一个实例以类型平安的办法来调用它要调用的线程办法。其次条语句正式开始该新线程,一旦办法Start()被调用,该线程就维持在一个"alive"的状态下了,你可以通过读取它的IsAlive属性来判定它是否处于"alive"状态。下面的语句显示了假如一个线程处于"alive"状态下就将该线程挂起的办法:if(thread.IsAlive){thread.Suspend();}不过请注重,线程对象的Start()办法只是启动了该线程,而并不担保其线程办法ThreadFunc()能立刻得到执行。它只是担保该线程对象能被分派到CPU时间,而实际的执行还要由驾驭体系依据办理器时间来决心。一个线程的办法不蕴涵任何参数,同时也不返回任何值。它的命名规矩和一般函数的命名规矩相同。它既可以是静态的(static)也可以长短静态的(nonstatic)。当它执行完结后,相应的线程也就结束了,其线程对象的IsAlive属性也就被置为false了。下面是一个线程办法的实例:publicstaticvoidThreadFunc(){for(inti=0;i%26lt;10;i++){Console.WriteLine("ThreadFunc{0}"i);}}前台线程和靠山线程.Net的公用语言运行时(CommonLanguageRuntime,CLR)能划分两种差异类型的线程:前台线程和靠山线程。这两者的辨别即是:应用程序必需运行一切面的前台线程才可以退出;而对于靠山线程,应用程序则可以不考虑其是否已经运行完结而直接退出,全面的靠山线程在应用程序退出时都市自动结束。一个线程是前台线程还是靠山线程可由它的IsBackground属性来决心。这个属性是可读又可写的。它的默认值为false,即意味着一个线程默觉得前台线程。我们可以将它的IsBackground属性设置为true,从而使之成为一个靠山线程。下面的例子是一个有效监管台程序,程序一开始便启动了10个线程,每个线程运行5秒钟时间。由于线程的IsBackground属性默觉得false,即它们都是前台线程,因此尽管程序的主线程很快就运行结束了,但程序要到全面已启动的线程都运行完结才会结束。示例代码如下:usingSystem;usingSystem.Threading;classMyApp{publicstaticvoidMain(){for(inti=0;i%26lt;10;i++){Threadthread=newThread(newThreadStart(ThreadFunc));thread.Start();}}privatestaticvoidThreadFunc(){DateTimestart=DateTime.Now;while((DateTime.Now-start).Seconds%26lt;5);}}接下来我们对上面的代码进行略微修改,将每个线程的IsBackground属性都设置为true,则每个线程都是靠山线程了。那么只要程序的主线程结束了,整个程序也就结束了。示例代码如下:usingSystem;usingSystem.Threading;classMyApp{publicstaticvoidMain(){for(inti=0;i%26lt;10;i++){Threadthread=newThread(newThreadStart(ThreadFunc));thread.IsBackground=true;thread.Start();}}privatestaticvoidThreadFunc(){DateTimestart=DateTime.Now;while((DateTime.Now-start).Seconds%26lt;5);}}既然前台线程和靠山线程有这种差别,那么我们怎么知道该怎样设置一个线程的IsBackground属性呢?下面是一些基本的原则:对于一些在靠山运行的线程,当程序结束时这些线程没有必要不断运行了,那么这些线程就应当设置为靠山线程。例如一个程序启动了一个进行多量运算的线程,可是只要程序一旦结束,那个线程就遗失了不断存在的意义,那么那个线程就该是作为靠山线程的。而对于一些服务于用户界面的线程频频是要设置为前台线程的,因为即使程序的主线程结束了,其他的用户界面的线程很可能要不断存在来显示相干的信息,因此不能立刻终止它们。这里我只是给出了一些原则,详细到实际的应用频频需要
编程者的进一步小心商量。线程优先级一旦一个线程开始运行,线程调剂程序就可以有效监管其所获得的CPU时间。假如一个托管的应用程序运行在Windows机器上,则线程调剂程序是由Windows所提供的。在其他的平台上,线程调剂程序可能是驾驭体系的一部分,也天然可能是.Net框架的一部分。不过我们这里不必考虑线程的调剂程序是怎样产生的,我们只要知道通过设置线程的优先级我们就可以使该线程获得差异的CPU时间。线程的优先级是由Thread.Priority属性有效监管的,其值蕴涵:ThreadPriority.Highest、ThreadPriority.AboveNormal、ThreadPriority.Normal、ThreadPriority.BelowNormal和ThreadPriority.Lowest。从它们的名称上我们天然可以知道它们的优先程度,因此这里就不多作介绍了。线程的默认优先级为ThreadPriority.Normal。理论上,具有相同优先级的线程会获得相同的CPU时间,不过在实际执行时,消息行列中的线程阻碍或是驾驭体系的优先级的提上等原因会导致具有相同优先级的线程会获得差异的CPU时间。不过从总体上来考虑仍可以忽略这种差异。你可以通过以下的办法来转变一个线程的优先级。thread.Priority=ThreadPriority.AboveNormal;或是:thread.Priority=ThreadPriority.BelowNormal;通过上面的首先句语句你可以提升一个线程的优先级,那么该线程就会相应的获得更多的CPU时间;通过其次句语句你便降低了那个线程的优先级,于是它就会被分派到比原先少的CPU时间了。你可以在一个线程开始运行前或是在它的运行过程中的任何时刻转变它的优先级。理论上你还可以任意的设置每个线程的优先级,不过一个优先级过高的线程频频会熏陶到其他线程的运行,甚至熏陶到其他程序的运行,因此最好不要随意的设置线程的优先级。挂起线程和从新开始线程Thread类分歧提供了两个办法来挂起线程和从新开始线程,也即是Thread.Suspend能暂停一个正在运行的线程,而Thread.Resume又能让那个线程不断运行。不像Windows内核,.Net框架是不记录线程的挂起次数的,因此不管你挂起线程过屡次,只要一次调用Thread.Resume就可以让挂起的线程从新开始运行。Thread类还提供了一个静态的Thread.Sleep办法,它能使一个线程自动的挂起肯定的时间,然后自动的从新开始。一个线程能在它本身内部调用Thread.Sleep办法,也能在本身内部调用Thread.Suspend办法,可是肯定要另外线程来调用它的Thread.Resume办法才可以从新开始。这一点是不是很轻易想通的啊?下面的例子显示了怎样应用Thread.Sleep办法:while(ContinueDrawing){DrawNextSlide();Thread.Sleep(5000);}终止线程在托管的代码中,你可以通过以下的语句在一个线程中将另一个线程终止掉:thread.Abort();下面我们来解说一下Abort()办法是怎样工作的。因为公用语言运行时治理了全面的托管的线程,同样它能在每个线程内抛出异常。Abort()办法能在方向线程中抛出一个ThreadAbortException异常从而导致方向线程的终止。不过Abort()办法被调用后,方向线程可能并不是立刻就终止了。因为只要方向线程正在调用非托管的代码并且还没有返回的话,该线程就不会立刻终止。而假如方向线程在调用非托管的代码并且陷入了一个死循环的话,该方向线程就基本不会终止。不过这种状况只是一些特例,更多的状况是方向线程在调用托管的代码,一旦Abort()被调用那么该线程就立刻终止了。在实际应用中,一个线程终止了另一个线程,不过频频要等那个线程一切终止了它才可以不断运行,这样的话我们就应当用