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

实例效果:

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线程处理消息队列中的其他消息。

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

时间: 2024-10-31 10:43:03

线程间通讯:WaitHandler使用实例及分析的相关文章

Java线程间通讯概述

这个故事源自一个很简单的想法:创建一个对开发人员友好的.简单轻量的线程间通讯框架,完全不 用锁.同步器.信号量.等待和通知,在Java里开发一个轻量.无锁的线程内通讯框架:并且也没有队列 .消息.事件或任何其他并发专用的术语或工具. 只用普通的老式Java接口实现POJO的通讯. 它可能跟Akka的类型化actor类似,但作为一个必须超级轻量,并且要针对单台多核计算机进行优化的 新框架,那个可能有点过了. 当actor跨越不同JVM实例(在同一台机器上,或分布在网络上的不同机器上)的进程边界时,

多线程编程之三——线程间通讯

七.线程间通讯 一般而言,应用程序中的一个次要线程总是为主线程执行特定的任务,这样,主线程和次要线程间必定有一个信息传递的渠道,也就是主线程和次要线程间要进行通信.这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的,下面将进行说明. 使用全局变量进行通信 由于属于同一个进程的各个线程共享操作系统分配该进程的资源,故解决线程间通信最简单的一种方法是使用全局变量.对于标准类型的全局变量,我们建议使用volatile 修饰符,它告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄

vc-【求助】VC++ 类间/线程间通讯问题

问题描述 [求助]VC++ 类间/线程间通讯问题 遇到这样一个问题,有两个类,一个为窗口类,一个为数据处理类.窗口中按下按钮后会启动两个线程,一个线程使数据处理类中的函数开始运行,另一个使进度条控件运行.数据处理类的函数需要在运行中不断将运行的结果传递给进度条的线程,请问该如何实现? 解决方案 两个线程之间的消息可以通过 PostThreadMessage 来传递. 解决方案二: 线程创建消息循环,CWinThread,然后可以通过PostThreadMessage来发送消息,接收到在消息循环中

线程间通讯-Java写交易客户端(多线程、对象数据传送等简单问题)

问题描述 Java写交易客户端(多线程.对象数据传送等简单问题) 有如下几个类: 1.Ticker类//此Ticker为简单java类,其属性与服务器传来的json字段对应,通过Decoder类反系列化json//反系列化以后的数据,用以做逻辑判断,符合逻辑,则向服务器发出某种请求 public class Ticker implements Serializable { private static final long serialVersionUID = 2015022601L; priv

多线程编程之 ---线程间通讯

下载源代码 七.线程间通讯 一般而言,应用程序中的一个次要线程总是为主线程执行特定的任务,这样,主线程和次要线程间必定有一个信息传递的渠道,也就是主线程和次要线程间要进行通信.这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的,下面将进行说明. 使用全局变量进行通信 由于属于同一个进程的各个线程共享操作系统分配该进程的资源,故解决线程间通信最简单的一种方法是使用全局变量.对于标准类型的全局变量,我们建议使用volatile 修饰符,它告诉编译器无需对该变量作任何的优化,即无需将

[JAVA100例]064、线程间通讯

/** * <p>Title: 线程间合作</p> * <p>Description: 本实例使用二个线程共同合作绘制一个实体三角.</p> * <p>Copyright: Copyright (c) 2003</p> * <p>Filename: mainThread.java</p> * @version 1.0 */ public class mainThread{ public static int f

深入Android Handler与线程间通信ITC的详解_Android

在<Android Handler之消息循环的深入解析>中谈到了Handler是用于操作线程内部的消息队列,所以Handler可以用来线程间通信ITC,这种方式更加安全和高效,可以大大减少同步的烦恼,甚至都可以不用syncrhonized.线程间通讯ITC正常情况下函数调用栈都会生存在同一个线程内,想要把执行逻辑交换到其他线程可以新建一个Thread,然后start().另外一种方法就是用ITC,也即用消息队列来实现,线程需要把执行逻辑交到其他线程时就向另外的线程的消息队列发送一个消息,发送消

深入Android Handler与线程间通信ITC的详解

在<Android Handler之消息循环的深入解析>中谈到了Handler是用于操作线程内部的消息队列,所以Handler可以用来线程间通信ITC,这种方式更加安全和高效,可以大大减少同步的烦恼,甚至都可以不用syncrhonized. 线程间通讯ITC 正常情况下函数调用栈都会生存在同一个线程内,想要把执行逻辑交换到其他线程可以新建一个Thread,然后start().另外一种方法就是用ITC,也即用消息队列来实现,线程需要把执行逻辑交到其他线程时就向另外的线程的消息队列发送一个消息,发

C++多线程编程(三)线程间通信

多线程编程之三--线程间通讯 作者:韩耀旭 原文地址:http://www.vckbase.com/document/viewdoc/?id=1707   七.线程间通讯 一般而言,应用程序中的一个次要线程总是为主线程执行特定的任务,这样,主线程和次要线程间必定有一个信息传递的渠道,也就是主线程和次要线程间要进行通信.这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的,下面将进行说明. 使用全局变量进行通信 由于属于同一个进程的各个线程共享操作系统分配该进程的资源,故解决线程间