博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程间通讯:WaitHandler使用实例及分析
阅读量:5936 次
发布时间:2019-06-19

本文共 3803 字,大约阅读时间需要 12 分钟。

实例效果:

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

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

Form1.cs

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading;namespace TestThread{    public partial class Form1 : Form    {        private ManualResetEvent Stop = new ManualResetEvent(false);//用于告诉线程t要关闭t线程        private ManualResetEvent Stoped = new ManualResetEvent(false);//用于告诉主线程t线程已关闭        Thread t = null;        private delegate void SetUIDelegate(string val);//用于线程t操作ui控件        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)//“启动线程”        {            MyThread mt = new MyThread(Stop, Stoped);            mt.UIEvent += (val) =>                {                    if (lbx.InvokeRequired)                        lbx.Invoke(new SetUIDelegate(SetUI), val);                    else                        lbx.Items.Add(val);                };            t = new Thread(() =>                {                    mt.Run();                });            t.Start();        }        private void button2_Click(object sender, EventArgs e)//“关闭线程”        {            if (null!=t&&t.IsAlive)//若线程t存在并存活才需关闭             {                Stop.Set();//发出指令告诉线程t:你是时候死了!                while (t.IsAlive)//因线程t不是马上自尽(也许还要吃个包、喝口茶在上吊哦!),所以要继续检查它是否存活                {                    if (Stoped.WaitOne(0, false))//阻塞当前线程(这里设置阻塞0秒),就是看看线程t死了没                    {                        button1.Enabled = false;                    }                     Application.DoEvents();//因ui线程一直在检查线程t的死活,弄得其他需要ui线程的处理都无法进行,加上这句ui线程就有时间理睬一下其他处理了,以免画面假死!                }            }          }        private void SetUI(string val)        {            lbx.Items.Add(val);        }    }}
MyThread.cs
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace TestThread{    public delegate void SetUI(string val);     class MyThread    {        private ManualResetEvent Stop = null;        private ManualResetEvent Stoped = null;        public event SetUI UIEvent;        public MyThread(ManualResetEvent stop,ManualResetEvent stoped)        {            Stop = stop;            Stoped = stoped;        }        public void Run()        {            int i = 0;            while (true)            {                Thread.Sleep(2000);//睡2秒再工作吧!                UIEvent(i.ToString());//操作ui控件                i++;                if (Stop.WaitOne(0, false))//阻塞当前线程(这里又只阻塞0秒),直到ui线程赐死线程t                {                    Stoped.Set();//告诉ui线程它要自杀了                    break;//自杀去了                }            }        }    }}

子线程之死可以有两种方式: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线程处理消息队列中的其他消息。

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

转载地址:http://rcntx.baihongyu.com/

你可能感兴趣的文章
[转载]---从30岁到35岁:为你的生命多积累一些厚度
查看>>
工作,但别忘了生活
查看>>
线程之死循环。
查看>>
字符串本地化
查看>>
详解著名的awk Oneliner,第三部分:选择性输出特定行
查看>>
objc 对时间的基本操作。取出时间
查看>>
C语言的编程风格
查看>>
iptables_cacti_nagios
查看>>
Ubuntu麒麟社区的行为准则(Code of Conduct)
查看>>
常用正则表达式总结
查看>>
C++容器类的简介
查看>>
SCTP 关联的建立和终止
查看>>
嵌入式开发之davinci--- mcfw框架介绍
查看>>
利用Google翻译成多国语言的见解
查看>>
164. Maximum Gap
查看>>
ubuntu下一个rootusername入口mysql,如何查看username和password,如何改变rootpassword
查看>>
scala 学习笔记(04) OOP(上)主从构造器/私有属性/伴生对象(单例静态类)/apply方法/嵌套类...
查看>>
使用mysql索引的规则
查看>>
K临近算法
查看>>
第五节,计算机(电脑)简介
查看>>