线程间通讯:WaitHandler使用实例及分析

简介:

实例效果:

1.点击“启动线程”会启动一个线程t每隔2秒在listbox上插入一条新记录。

2.点击“关闭线程”会停止线程t,但不是马上停止而是等待线程t当次循环的工作后再结束。

Form1.cs

复制代码
 1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Windows.Forms;
9 using System.Threading;
10
11 namespace TestThread
12 {
13 public partial class Form1 : Form
14 {
15 private ManualResetEvent Stop = new ManualResetEvent(false);//用于告诉线程t要关闭t线程
16 private ManualResetEvent Stoped = new ManualResetEvent(false);//用于告诉主线程t线程已关闭
17 Thread t = null;
18 private delegate void SetUIDelegate(string val);//用于线程t操作ui控件
19
20 public Form1()
21 {
22 InitializeComponent();
23 }
24
25 private void button1_Click(object sender, EventArgs e)//“启动线程”
26 {
27 MyThread mt = new MyThread(Stop, Stoped);
28 mt.UIEvent += (val) =>
29 {
30 if (lbx.InvokeRequired)
31 lbx.Invoke(new SetUIDelegate(SetUI), val);
32 else
33 lbx.Items.Add(val);
34 };
35 t = new Thread(() =>
36 {
37 mt.Run();
38 });
39 t.Start();
40 }
41
42 private void button2_Click(object sender, EventArgs e)//“关闭线程”
43 {
44 if (null!=t&&t.IsAlive)//若线程t存在并存活才需关闭
45 {
46 Stop.Set();//发出指令告诉线程t:你是时候死了!
47
48 while (t.IsAlive)//因线程t不是马上自尽(也许还要吃个包、喝口茶在上吊哦!),所以要继续检查它是否存活
49 {
50 if (Stoped.WaitOne(0, false))//阻塞当前线程(这里设置阻塞0秒),就是看看线程t死了没
51 {
52 button1.Enabled = false;
53 }
54 Application.DoEvents();//因ui线程一直在检查线程t的死活,弄得其他需要ui线程的处理都无法进行,加上这句ui线程就有时间理睬一下其他处理了,以免画面假死!
55 }
56 }
57 }
58
59 private void SetUI(string val)
60 {
61 lbx.Items.Add(val);
62 }
63 }
64 }
复制代码

MyThread.cs

复制代码
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6
7 namespace TestThread
8 {
9 public delegate void SetUI(string val);
10
11 class MyThread
12 {
13 private ManualResetEvent Stop = null;
14 private ManualResetEvent Stoped = null;
15 public event SetUI UIEvent;
16
17 public MyThread(ManualResetEvent stop,ManualResetEvent stoped)
18 {
19 Stop = stop;
20 Stoped = stoped;
21 }
22
23 public void Run()
24 {
25 int i = 0;
26 while (true)
27 {
28 Thread.Sleep(2000);//睡2秒再工作吧!
29 UIEvent(i.ToString());//操作ui控件
30 i++;
31 if (Stop.WaitOne(0, false))//阻塞当前线程(这里又只阻塞0秒),直到ui线程赐死线程t
32 {
33 Stoped.Set();//告诉ui线程它要自杀了
34 break;//自杀去了
35 }
36 }
37 }
38 }
39 }
复制代码

子线程之死可以有两种方式:1、ui线程中调用t.Abort(),为它杀,也许线程t还有些事没做但已经没有机会了;2、让线程t退出或调用Thread.CurrentThread.Abort(),为自杀,这样线程t就可以在临死前了结心愿了。而上述功能就属于让线程t自杀,下面进一步分析。

线程t无缘无故是不会自杀的,而ui线程要它自刎就必须发出一条命令,而这条命令就是ManualResetEvent对象。先看一看类结构

可以看到ManualResetEvent类有一个孪生兄弟AutoResetEvent类,它们的祖父是WaitHandle类。

ManualResetEvent实例有终止和非终止两个状态,在初始化时可以设定。它的Set()方法会将实例设为终止状态,Reset()方法会将实例设为非终止状态。而WaitOne()就是阻塞当前线程直到实例被设为终止状态,而WaitOne()方法有多个重载方法,可以设定阻塞时间,超过了阻塞时间实例状态依然为非终止的话就放弃阻塞,让线程继续执行WaitOne语句以下的内容。WaitOne返回值为Boolean值,表示实例状态是否为终止状态。

AutoResetEvent类跟ManualResetEvent类只有一点区别就是它会自动把实例设为非终止状态。

而使用WaitHandle的静态方法WaitAll或WaitAny可以检查多个ManualResetEvent实例和AutoResetEvent实例的状态。

上述代码中线程t自杀时通过另一个ManualResetEvent实例告诉ui线程“我挂了!”,好让ui线程做善后工作。

检查线程t是否已死的过程是一直占用ui线程的,而窗口上控件的交互也是由ui线程来处理,这时会出现画面假死的状态,如果发出了调用ui线程处理其他事件的话就会有异常。这时加上一句Application.DoEvents()表示让处理当前消息队列中的所有window消息,就是说ui线程抽出一部分时间来处理消息队列中的其他消息(如界面的交互),而不是完成了第一个消息再着手后面的消息。注意:这时ui线程是可用的,只是正忙于处理第一个消息,如果ui线程挂起来了、阻塞了或死了Application.DoEvents()无法使让ui线程处理消息队列中的其他消息。


要实现上述的子线程自杀方式也可以用两个静态变量来做控制,至于实现方法我这里就不写了。



如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!


本文转自^_^肥仔John博客园博客,原文链接:http://www.cnblogs.com/fsjohnhuang/archive/2012/01/11/2319253.html,如需转载请自行联系原作者

相关文章
|
2月前
|
存储 NoSQL Redis
Redis 新版本引入多线程的利弊分析
【10月更文挑战第16天】Redis 新版本引入多线程是一个具有挑战性和机遇的改变。虽然多线程带来了一些潜在的问题和挑战,但也为 Redis 提供了进一步提升性能和扩展能力的可能性。在实际应用中,我们需要根据具体的需求和场景,综合评估多线程的利弊,谨慎地选择和使用 Redis 的新版本。同时,Redis 开发者也需要不断努力,优化和完善多线程机制,以提供更加稳定、高效和可靠的 Redis 服务。
65 1
|
2月前
线程CPU异常定位分析
【10月更文挑战第3天】 开发过程中会出现一些CPU异常升高的问题,想要定位到具体的位置就需要一系列的分析,记录一些分析手段。
82 0
|
24天前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
43 4
|
3月前
|
并行计算 API 调度
探索Python中的并发编程:线程与进程的对比分析
【9月更文挑战第21天】本文深入探讨了Python中并发编程的核心概念,通过直观的代码示例和清晰的逻辑推理,引导读者理解线程与进程在解决并发问题时的不同应用场景。我们将从基础理论出发,逐步过渡到实际案例分析,旨在揭示Python并发模型的内在机制,并比较它们在执行效率、资源占用和适用场景方面的差异。文章不仅适合初学者构建并发编程的基础认识,同时也为有经验的开发者提供深度思考的视角。
|
4月前
|
存储 监控 Java
|
4月前
|
安全 Java 开发者
Swing 的线程安全分析
【8月更文挑战第22天】
72 4
|
3月前
|
安全 Java API
Java线程池原理与锁机制分析
综上所述,Java线程池和锁机制是并发编程中极其重要的两个部分。线程池主要用于管理线程的生命周期和执行并发任务,而锁机制则用于保障线程安全和防止数据的并发错误。它们深入地结合在一起,成为Java高效并发编程实践中的关键要素。
34 0
|
3天前
|
NoSQL Redis
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
12 1
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
60 1
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
32 3