分享
 
 
 

C#多线程应用技术面对面探讨

王朝c#·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

实例程序说明

本文的实例程序包括一个列表框、三个按钮。程序使用一个新的线程来运行一个后台处理,结果在列表框中显示。按钮button1启动一个计算平方的线程。按钮button2停止后台处理线程。按钮button3退出程序。程序运行情况如图1所示。

使用线程

首先创建运行在新线程上的后台任务。表1所示的代码执行一个相当长的运行处理----一个无限循环。

表1、后台处理程序

private void BackgroundProcess()

{

int i= 1;

while(true)

{

//

向列表框增加一个项目

listBox1.Items.Add("Iterations: " + i.ToString ());

i ++;

Thread.Sleep(2000);

//

指定线程休眠的时间

}

}

这段代码无限循环,每次执行时在列表框中加入一个项目。

在规定好一个工作的处理代码以后,就需要将这段代码分配给一个线程,并且启动它。为此需要使用线程对象(Thread object),它是.NET架构类中System.Threading命名空间的一部分。在实例化一个新的线程类时,需要把在线程类构造器中执行的代码块的一个引用传送给该实例。表2所示的代码创建一个新的线程对象,并且将BackgroundProcess的一个引用传送给该对象。

表2、线程的使用

Thread t1,t2;

//

说明为窗体类成员

t1 = new Thread(new ThreadStart(BackgroundProcess));

t1.Start();

//

以上2行放置在窗体的load事件中

ThreadStart表示在线程上执行的方法,这里是一个到BackgroundProcess方法的委派对象。在C#中,一个委派是一个类型安全、面向对象的函数指针。在实例化该线程后,可以通过调用线程的Start()方法来开始执行代码。

控制线程

在线程启动以后,可以通过调用线程对象的方法来控制线程的状态。可以通过调用Thread.Sleep方法来暂停一个线程的执行,这个方法可以接收一个整型值,用来决定线程休眠的时间。对于本文的实例程序,为了让列表项目增加的速度变慢,在其中放入了一个Sleep方法的调用。

可以通过调用Thread.Sleep(System.Threading.Timeout.Infinite)来让线程进入休眠状态,但是,这个调用的休眠时间是不确定的。要中断这个休眠,可以调用Thread.Interrupt方法。

通过调用Thread.Suspend方法可以挂起线程。挂起可以暂停一个线程,直到另一个线程调用Thread.Resume为止。休眠和挂起的区别是,挂起并不立刻让线程进入一个等待的状态,线程并不会挂起,直到.NET runtime认为现在已经是一个安全的地方来挂起它了,而休眠则会立刻让线程进入一个等待的状态。

表3、停止线程的执行

private void button2_Click

(object sender, System.EventArgs e)

{

t1.Abort();

}

Thread.Abort方法可以停止一个线程的执行。本文的实例程序通过加入一个按钮button2来停止后台处理,在事件处理程序中调用了Thread.Abort方法,如表3所示。

这就是多线程的强大之处。用户界面的响应很快,因为用户界面运行在一个单独的线程中,而后台的处理运行在另外一个线程中。在用户按下按钮button2时,就会马上得到响应,并且停止后台处理。

通过多线程程序传送数据

在实际工作中,还需要使用到多线程的许多复杂特性。其中一个问题就是如何将程序的数据由线程类的构造器传入或者传出。对于放到另外一个线程中的过程,既不能传参数给它,也不能由它返回值,因为传入到线程构造器的过程是不能拥有任何参数或者返回值的。为了解决这个问题,可以将过程封装到一个类中,这样,方法的参数就可使用类中的字段。

本文给出了一个简单的例子,计算一个数的平方。为了在一个新的线程中使用这个过程,将它封装到一个类中,如表4所示。

使用表5所示的代码在一个新的线程上启动CalcSquare过程。

表4、计算一个数的平方

表5、在一个新的线程上启动CalcSquare过程

public class SquareClass

{

public

double Value;

public double Square;

public void CalcSquare()

{

Square = Value * Value;

}

}

private void button1_Click(object sender, System.EventArgs e)

{

SquareClass oSquare =new SquareClass();

t2 = new Thread(new ThreadStart(oSquare.CalcSquare));

oSquare.Value = 30;

t2.Start();

}

在上述例子中,线程启动后,并没有检查类中的square值,因为即使调用了线程的start方法,也不能确保其中的方法马上执行完。要从另一个线程中得到需要的值,有几种方法,其中一种方法就是在线程完成的时候触发一个事件。表6所示的代码为SquareClass加入了事件声明。

表6、为SquareClass加入事件声明

public delegate void EventHandler(double sq);

//

说明委派类型

public class SquareClass

{

public

double Value;

public double Square;

public event EventHandler ThreadComplete;

//

说明事件对象

public void CalcSquare()

{

Square = Value * Value;

//

指定事件处理程序

ThreadComplete+=new EventHandler(SquareEventHandler);

if( ThreadComplete!=null)ThreadComplete(Square);

//

触发事件

}

public static void SquareEventHandler(double

Square )

//

定义事件处理程序

{

MessageBox.Show(Square.ToString ());

}

}

对于这种方法,要注意的是事件处理程序SquareEventHandler运行在产生该事件的线程t2中,而不是运行在窗体执行的线程中。

同步线程

在线程的同步方面,C#提供了几种方法。在上述计算平方的例子中,需要与执行计算的线程同步,以便等待它执行完并且得到结果。另一个例子是,如果在其它线程中排序一个数组,那么在使用该数组前,必须等待该处理完成。为了实现同步,C#提供了lock声明和Thread.Join方法。

lock声明

表7、使用lock声明

public void CalcSquare1()

{

lock( typeof(SquareClass))

{

Square = Value * Value;

}

}

lock可以得到一个对象引用的唯一锁,使用时只要将该对象传送给lock就行了。通过这个唯一锁,可以确保多个线程不会访问共享的数据或者在多个线程上执行的代码。要得到一个锁,可以使用与每个类关联的System.Type对象。System.Type对象可以通过使用typeof运算得到,如表7所示。

Thread.Join方法

表8、使用Thread.Join方法

private void button1_Click(object sender, System.EventArgs e)

{

SquareClass oSquare =new SquareClass();

t2 = new Thread(new ThreadStart(oSquare.CalcSquare));

oSquare.Value = 30;

t2.Start();

if( t2.Join (500) )

{

MessageBox.Show(oSquare.Square.ToString ());

}

}

Thread.Join方法可以等待一个特定的时间,直到一个线程完成。如果该线程在指定的时间内完成了,Thread.Join将返回True,否则它返回False。在上述平方的例子中,如果不想使用触发事件的方法,可以调用Thread.Join的方法来确定计算是否完成了。代码如表8所示。

结论

本文通过一个实例程序说明了C#中线程的使用和控制方法,探讨了如何通过多线程程序传送数据和线程的同步问题。根据本文的分析可知,在C#中,使用线程是很简单的。C#支持建立自由线程的应用,提高了资源的利用率,程序的响应速度也得到了改善。当然也带来了数据传送和线程同步等问题。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有