现在的位置: 首页 > 综合 > 正文

线程(精)

2013年07月09日 ⁄ 综合 ⁄ 共 6360字 ⁄ 字号 评论关闭

转帖地址:http://blog.csdn.net/Knight94/archive/2006/08/24/1111267.aspx

 

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

抱歉!评论已关闭.