首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET >

CSDN第一期总结之三:Thread的有关问题

2012-02-05 
CSDN第一期总结之三:Thread的问题C#是一门支持多线程的语言,因此线程的使用也是比较常见的。由于线程的知识

CSDN第一期总结之三:Thread的问题
C#是一门支持多线程的语言,因此线程的使用也是比较常见的。由于线程的知识在Win32编程的时候已经说得过多,所以在.Net中很少介绍这部分(可能.Net不觉得这部分是它所特有的)。

 

那么线程相关的问题大致有如下四类(这篇文章只讨论单线程、单线程与UI线程这两方面的问题)。

问题一,线程的基本操作,例如:暂停、继续、停止等;

问题二,如何向线程传递参数或者从中得到其返回值;

问题三,如何使线程所占用的CPU不要老是百分之百;

最后一个,也是问题最多的,就是如何在子线程来控制UI中的控件,换句话说,就是在线程中控制窗体某些控件的显示。

 

对于问题一,我不建议使用Thread类提供的Suspend、Resume以及Abort这三个方法,前两个有问题,好像在VS05已经屏蔽这两个方法;对于Abort来说,除了资源没有得到及时释放外,有时候会出现异常。如何做呢,通过设置开关变量来完成。

 

对于问题二,我不建议使用静态成员来完成,仅仅为了线程而破坏类的封装有些得不偿失。那如何做呢,通过创建单独的线程类来完成。

 

对于问题三来说,造成这个原因是由于线程中进行不间断的循环操作,从而使CPU完全被子线程占有。那么处理此类问题,其实很简单,在适当的位置调用Thread.Sleep(20)来释放所占有CPU资源,不要小看这20毫秒的睡眠,它的作用可是巨大的,可以使其他线程得到CPU资源,从而使你的CPU使用效率降下来。

 

看完前面的三个问题的解释,对于如何做似乎没有给出一个明确的答案,为了更好地说明如何解决这三个问题,我用一个比较完整的例子展现给大家,代码如下。

//--------------------------- Sub-thread class ---------------------------------------

//------------------------------------------------

//---File: clsSubThread

//---Description: The sub-thread template class file 

//---Author: Knight

//---Date: Aug.21, 2006

//------------------------------------------------

//---------------------------{Sub-thread class}---------------------------------------

namespace ThreadTemplate

{

  using System;

  using System.Threading;

  using System.IO;

  /// <summary>

  /// Summary description for clsSubThread.

  /// </summary>

  public class clsSubThread:IDisposable

  {

  private Thread thdSubThread = null;

  private Mutex mUnique = new Mutex();

 

  private bool blnIsStopped;

  private bool blnSuspended;

  private bool blnStarted;

  private int nStartNum;

 

  public bool IsStopped

  {

  get{ return blnIsStopped; }

  }

  public bool IsSuspended

  {

  get{ return blnSuspended; }

  }

  public int ReturnValue

  {

  get{ return nStartNum;}

  }

 

   

  public clsSubThread( int StartNum )

  {

  //

  // TODO: Add constructor logic here

  //

  blnIsStopped = true;

  blnSuspended = false;

  blnStarted = false;

   

  nStartNum = StartNum;

  }

 

  /// <summary>

  /// Start sub-thread

  /// </summary>

  public void Start()

  {

  if( !blnStarted )

  {

  thdSubThread = new Thread( new ThreadStart( SubThread ) );

  blnIsStopped = false;

  blnStarted = true;

  thdSubThread.Start();

  }

  }

 

  /// <summary>

  /// Thread entry function

  /// </summary>

  private void SubThread()

  {



  do

  {

  // Wait for resume-command if got suspend-command here  

  mUnique.WaitOne();

  mUnique.ReleaseMutex();

 

  nStartNum++;

   

  Thread.Sleep(1000); // Release CPU here

  }while( blnIsStopped == false );

  }

 

  /// <summary>

  /// Suspend sub-thread

  /// </summary>

  public void Suspend()

  {

  if( blnStarted && !blnSuspended )

  {

  blnSuspended = true;

  mUnique.WaitOne();

  }

  }

   

  /// <summary>

  /// Resume sub-thread

  /// </summary>

  public void Resume()

  {

  if( blnStarted && blnSuspended )

  {

  blnSuspended = false;

  mUnique.ReleaseMutex();

  }

  }

 

  /// <summary>

  /// Stop sub-thread

  /// </summary>

  public void Stop()

  {

  if( blnStarted )

  {

  if( blnSuspended )

  Resume();

 

  blnStarted = false;

  blnIsStopped = true;

  thdSubThread.Join();

  }

  }

  #region IDisposable Members

  /// <summary>

  /// Class resources dispose here

  /// </summary>

  public void Dispose()

  {

  // TODO: Add clsSubThread.Dispose implementation

  Stop();//Stop thread first

  GC.SuppressFinalize( this );

  }

 

  #endregion

  }

}

 

那么对于调用呢,就非常简单了,如下:

  // Create new sub-thread object with parameters

  clsSubThread mySubThread = new clsSubThread( 5 );

 

  mySubThread.Start();//Start thread

   

  Thread.Sleep( 2000 );

  mySubThread.Suspend();//Suspend thread 

 

  Thread.Sleep( 2000 );

  mySubThread.Resume();//Resume thread 

 

  Thread.Sleep( 2000 );

  mySubThread.Stop();//Stop thread 

 

  //Get thread's return value

  Debug.WriteLine( mySubThread.ReturnValue );

 

  //Release sub-thread object

  mySubThread.Dispose();

 

在回过头来看看前面所说的三个问题。

对于问题一来说,首先需要局部成员的支持,那么

  private Mutex mUnique = new Mutex();

 

  private bool blnIsStopped;

  private bool blnSuspended;

  private bool blnStarted;

 

光看成员名称,估计大家都已经猜出其代表的意思。接下来需要修改线程入口函数,要是这些开关变量能发挥作用,那么看看SubThread这个函数。



  /// <summary>

  /// Thread entry function

  /// </summary>

  private void SubThread()

  {

  do

  {

  // Wait for resume-command if got suspend-command here  

  mUnique.WaitOne();

  mUnique.ReleaseMutex();

 

  nStartNum++;

   

  Thread.Sleep(1000);

  }while( blnIsStopped == false );

  }

 

函数比较简单,不到十句,可能对于“blnIsStopped == false”这个判断来说,大家还比较好理解,这是一个普通的判断,如果当前Stop开关打开了,就停止循环;否则一直循环。

大家比较迷惑的可能是如下这两句:

  mUnique.WaitOne();

  mUnique.ReleaseMutex();

这两句的目的是为了使线程在Suspend操作的时候能发挥效果,为了解释这两句,需要结合Suspend和Resume这两个方法,它俩的代码如下。

  /// <summary>

  /// Suspend sub-thread

  /// </summary>

  public void Suspend()

  {

  if( blnStarted && !blnSuspended )

  {

  blnSuspended = true;

  mUnique.WaitOne();

  }

  }

   

  /// <summary>

  /// Resume sub-thread

  /// </summary>

  public void Resume()

  {

  if( blnStarted && blnSuspended )

  {

  blnSuspended = false;

  mUnique.ReleaseMutex();

  }

  }

 

为了更好地说明,还需要先简单说说Mutex类型。对于此类型对象,当调用对象的WaitOne之后,如果此时没有其他线程对它使用的时候,就立刻获得信号量,继续执行代码;当再调用ReleaseMutex之前,如果再调用对象的WaitOne方法,就会一直等待,直到获得信号量的调用ReleaseMutex来进行释放。这就好比卫生间的使用,如果没有人使用则可以直接使用,否则只有等待。

明白了这一点后,再来解释这两句所能出现的现象。

  mUnique.WaitOne();

  mUnique.ReleaseMutex();

 

当在线程函数中,执行到“mUnique.WaitOne();”这一句的时候,如果此时外界没有发送Suspend消息,也就是信号量没有被占用,那么这一句可以立刻返回。那么为什么要紧接着释放呢,因为不能总占着信号量,立即释放信号量是避免在发送Suspend命令的时候出现等待;如果此时外界已经发送了Suspend消息,也就是说信号量已经被占用,此时“mUnique.WaitOne();”不能立刻返回,需要等到信号量被释放才能继续进行,也就是需要调用Resume的时候,“mUnique.WaitOne();”才能获得信号量进行继续执行。这样才能达到真正意义上的Suspend和Resume。

 

至于线程的Start和Stop来说,相对比较简单,这里我就不多说了。

 



[解决办法]
沙发~
[解决办法]
up
[解决办法]
不错,友情顶一下。
[解决办法]
UP
[解决办法]
學習
[解决办法]
up
[解决办法]
学习了
[解决办法]
谢谢
[解决办法]
学习中...
[解决办法]
Mark 刚好想学线程的内容

热点排行