一、WaitHandler的类层次

可以看到 WaitHandle是 事件(EventWaitHandle)、互斥体(Mutex)、信号量(Sempahore)的父类。

WaitHandle我们最经常使用的方法,并是使用它的静态方法WaitAll. 我们会发现在这个WaitHandle里面只有等待方法,也就是它会阻塞当前线程的执行。

那么如何要解除它对当前线程的阻塞呢,那么就需要依赖于各个子类的方法了。

例如现在有一个这样的场景,如何在一个方法中,等待所有的线程全部执行完,最后再统计得到的计算结果呢?

WaitHandle[] handlers = new WaitHandle[]{
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false)
}; for (var i = 0; i < handlers.Length; i++)
{
ThreadPool.QueueUserWorkItem(ar =>
{
int index = (int)ar;
Thread.Sleep(1000);
AppCenter.AppendLog("任务:" + index + "开始执行!");
(handlers[index] as AutoResetEvent).Set();
}, i);
} ThreadPool.QueueUserWorkItem(ar =>
{
WaitHandle.WaitAll(handlers);
AppCenter.AppendLog("所有任务都已经完成了,我不用再等待了。");
});

运行结果如下:

二、EventWaitHandle

这个方法,可以方便实现两个线程之间的相互通信。

如何实现两个线程的相互通信?

EventWaitHandle handleA = new AutoResetEvent(false);
EventWaitHandle handleB = new AutoResetEvent(false); ThreadPool.QueueUserWorkItem(ar =>
{
AppCenter.AppendLog("A:我是A,我已经开始运行了");
Thread.Sleep(2000);
AppCenter.AppendLog("A:我想睡觉了,B你先跑跑吧。");
EventWaitHandle.SignalAndWait(handleB, handleA);
AppCenter.AppendLog("A:开始工作ing");
Thread.Sleep(3000);
AppCenter.AppendLog("A:这个有点难,问下B");
EventWaitHandle.SignalAndWait(handleB, handleA);
AppCenter.AppendLog("A:不错,今天任务搞定,我也闪人了。");
}); ThreadPool.QueueUserWorkItem(ar =>
{
handleB.WaitOne();
AppCenter.AppendLog("B:我是B,我已经顶替A开始运行了。");
Thread.Sleep(5000);
AppCenter.AppendLog("B:我的事情已经做完了,该让A搞搞了,休息一会。");
EventWaitHandle.SignalAndWait(handleA, handleB);
AppCenter.AppendLog("B:hi,A我搞定了,下班了。");
handleA.Set();
});

运行结果如下:

那么AutoResetEvent和ManualResetEvent有什么区别呢?我们先做个实验。

private EventWaitHandle manualEvent = new ManualResetEvent(false);

private void ManualResetEvent_Click(object sender, EventArgs e)
{ AppCenter.CleanLogs(); ThreadPool.QueueUserWorkItem(ar =>
{
int i = 0;
while (true)
{
manualEvent.WaitOne(); //ManualResetEvent的Set()方法,让事件的终止状态永远为true,让这里一直能执行。
i++; //而AutoResetEvent的Set()方法,初始化让这里执行一次,然后再次执行时是非终止的。将阻塞原有线程的执行
AppCenter.AppendLog("#" + i.ToString());
Thread.Sleep(1000);
}
});
} private void button2_Click(object sender, EventArgs e)
{
manualEvent.Set();
} private void button3_Click(object sender, EventArgs e)
{
manualEvent.Reset();
}

运行结果

我们会发现ManualResetEvent在触发Set()方法会,解除了原有的线程的 WaitOne方法,会一直打印输出。

而当我们替换为AutoResetEvent方法时候。

此时每次只会打印一个输出。因为它将 事件的状态设置为终止后,又变为了false.

三、Semaphore 控制并行线程的执行

应用场景,如果有多个线程跑,我能否每次控制3个线程一起跑呢。

Semaphore sempore = new Semaphore(0, 3);
for (int i = 0; i < 8; i++)
{
ThreadPool.QueueUserWorkItem(ar =>
{
sempore.WaitOne();
AppCenter.AppendLog("\t第:" +((int)ar).ToString() + "个开始运行.");
},i);
}
ThreadPool.QueueUserWorkItem(ar =>
{
for (int i = 0; i < 3; i++)
{
AppCenter.AppendLog("第" + (i + 1).ToString() + "批开始执行.");
sempore.Release(3);
Thread.Sleep(5000);
}
});

运行结果:

C# 多线程通信详解的更多相关文章

  1. Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解

    Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解 (本文转自: http://blog.csdn.net/yinhaide/article/details/44756 ...

  2. .NET多线程同步方法详解

    .NET多线程同步方法详解(一):自由锁(InterLocked) .NET多线程同步方法详解(二):互斥锁(lock) NET多线程同步方法详解(三):读写锁(ReadWriteLock) .NET ...

  3. Android Socket通信详解

    一.Socket通信简介  Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客 ...

  4. SSL握手通信详解及linux下c/c++ SSL Socket代码举例

    SSL握手通信详解及linux下c/c++ SSL Socket代码举例 摘自:http://www.169it.com/article/3215130236.html   分享到:8     发布时 ...

  5. SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码)

    SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码) 摘自: https://blog.csdn.net/sjin_1314/article/det ...

  6. Java多线程——多线程方法详解

    本系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线程的深入剖 ...

  7. 开源项目SMSS发开指南(五)——SSL/TLS加密通信详解(下)

    继上一篇介绍如何在多种语言之间使用SSL加密通信,今天我们关注Java端的证书创建以及支持SSL的NioSocket服务端开发.完整源码 一.创建keystore文件 网上大多数是通过jdk命令创建秘 ...

  8. java网络编程Socket通信详解

    Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket.像大家熟悉的QQ.MSN都使用了Socket相关的技术. ...

  9. Swift - 多线程GCD详解

    //  GCD详解 //  目录: //  1. 创建GCD队列(最常用) //  2. 自定义创建队列 //  3. 使用多线程实现延迟加载 //  4. 使用多线程实现重复(循环) //  5. ...

随机推荐

  1. MMDrawerController第三方库的使用(根据导航item+滚动条progressView实现的手势滑动切换视图的)

    https://github.com/mutualmobile/MMDrawerController MMDrawerControlleris边抽屉导航容器视图控制器用来支持越来越多的应用程序利用抽屉 ...

  2. Unity3D 2D游戏中寻径算法的一些解决思路

    需求 unity3d的3d开发环境中,原生自带了Navigation的组件,可以很便捷快速的实现寻路功能.但是在原生的2d中并没有相同的功能. 现在国内很多手机游戏都有自动寻路的功能,或者游戏中存在一 ...

  3. 学习之路三十五:Android和WCF通信 - 大数据压缩后传输

    最近一直在优化项目的性能,就在前几天找到了一些资料,终于有方案了,那就是压缩数据. 一丶前端和后端的压缩和解压缩流程 二丶优点和缺点 优点:①字符串的压缩率能够达到70%-80%左右 ②字符串数量更少 ...

  4. 编写高质量代码改善C#程序的157个建议[为类型输出格式化字符串、实现浅拷贝和深拷贝、用dynamic来优化反射]

    前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议13.为类型输出格式化字符串 建议14.正确实现浅拷贝和深 ...

  5. c# 通过反射获取私有方法

    class Program { static void Main(string[] args) { //通过反射来调私有的成员 Type type = typeof(Person); //Bindin ...

  6. Moqui学习Day1

    运行时目录以及Moqui的xml配置文件 Moqui框架部署运行主要有三个核心部分: 可执行的war包文件 运行时目录 Moqui配置文件XML格式 不管怎么使用这个可执行的war文件,你必须拥有一个 ...

  7. hdu1535 SPFA

    2边SPFA 然后求和 #include<stdio.h> #include<string.h> #include<queue> #define INF 10000 ...

  8. HP 电脑装 纯净版的win7

    新买的 HP 电脑,自带 Win10 的操作系统,今天把它改成 装win7 系统 在安装的过程中遇到的问题 1.数字证书错误.您安装的操作系统来源不明之类的错误,具体没有记下来 2.磁盘的格式不是NT ...

  9. BZOJ-1013 球形空间产生器sphere 高斯消元+数论推公式

    1013: [JSOI2008]球形空间产生器sphere Time Limit: 1 Sec Memory Limit: 162 MB Submit: 3662 Solved: 1910 [Subm ...

  10. python包的概念

    1 python程序由包(package).模块(module)和函数组成.包是由一系列模块组成的集合.模块是处理某一类问题的函数和类的集合. 2 包就是一个完成特定任务的工具箱. 3 包必须含有一个 ...