读书人

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

发布时间: 2012-02-05 12:07:14 作者: rapoo

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 刚好想学线程的内容

读书人网 >.NET

热点推荐