-
C#教程之深入多线程之:双向信号与竞赛的用法分
双向信号和竞赛(Two-Way Signaling and Races)
Monitor.Pulse方法的一个重要特性是它是异步执行的,这意味着调用pulse方法并不会阻塞自己等待Monitor.Pulse返回。如果任何一个线程在pulsed 对象上等待,它是不会阻塞的,换句话说,调用Monitor.Pulse对程序不会有什么作用,你可以认为Monitor.Pulse方法被忽略了。
这样Pulse提供了一个单向通信:一个 pulsing线程悄悄的向一个waiting 线程发送信号。
Pulse并不会返回一个值来告诉你waiting线程是否收到信号。
但是有时候我们需要知道waiting线程是否受到信号,例如下面的例子:
复制代码 代码如下:
class Race
{
static readonly object _locker = new object();
static bool _go;
public static void MainThread()
{
new Thread(SaySomething).Start();
for (int i = 0; i < 5; i++)
{
lock (_locker)
{
_go = true;
Monitor.PulseAll(_locker); //通知等待的队列
}
}
}
static void SaySomething()
{
for (int i = 0; i < 5; i++)
{
lock (_locker)
{
while (!_go) Monitor.Wait(_locker); //如果_go 为false,那么开始阻塞。
_go = false;
Console.WriteLine("Wassup?");
}
}
}
}
期待的输出:
Wassup?
Wassup?
Wassup?
Wassup?
Wassup?
实际的输出:
Wassup? (线程等待)
在SaySomething方法中,for循环执行到while,此时_go为false,所以Monitor.Wait开始等待。在MainThread中,for循环设置_go为true。然后PulseAll.但是PulseAll方法是异步的。
所以在SaySomething线程被唤醒前,mainThread中的for循环可能已经执行完毕。所以SaySomething方法中的第一个Wait线程收到消息词是_go为true,所以往下执行,再次将_go字段设置为false。输出”Wassup?”,但是下次循环由于_go为false,所以需要再次wait.所以实际的输出打印了一个Wassup,然后开始等待。
我们需要主线程在每一次迭代中如果worker仍然在执行上一个任务,那么主线程阻塞。等到worker执行完毕,那么主线程恢复执行,然后执行迭代。
我们可以增加一个_ready 标志,从而控制主线程在设置_go 标志之前worker线程已经ready了。也就是说主线程在设置_go之前,会等待worker完成任务,然后等待worker将ready设为true,当worker将ready设置为true后,通过pulse来通知主线程。
复制代码 代码如下:
class Race
{
static readonly object _locker = new object();
static bool _ready, _go;
public static void MainThread()
{
new Thread(SaySomething).Start();
for (int i = 0; i < 5; i++)
{
lock (_locker)
{
while (!_ready) Monitor.Wait(_locker); //如果worker的ready为false,则等待worker。
_ready = false; //重置标志
_go = true;
Monitor.PulseAll(_locker);
}
}
}
static void SaySomething()
{
for (int i = 0; i < 5; i++)
{
lock (_locker)
{
_ready = true; //将ready设置为true
Monitor.PulseAll(_locker); //通知主线程,worker已经ready了,可以执行任务了。
while (!_go) Monitor.Wait(_locker);
_go = false;
Console.WriteLine("Wassup?");
}
}
}
}
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比
一款纯 JS 实现的轻量化图片编辑器
关于开发 VS Code 插件遇到的 workbench.scm.
前端设计模式——观察者模式
前端设计模式——中介者模式
创建型-原型模式