C#多线程(8):线程完成数
解决一个问题
假如,程序需要向一个 Web 发送 5 次请求,受网路波动影响,有一定几率请求失败。如果失败了,就需要重试。
示例代码如下:
class Program
{
private static int count = 0;
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
new Thread(HttpRequest).Start(); // 创建线程
// 用于不断向另一个线程发送信号
while (count < 5)
{
Thread.Sleep(100);
}
Console.WriteLine("任务执行完毕");
}
// 模拟网络请求
public static void HttpRequest()
{
Console.WriteLine("开始一个任务");
// 随机生成一个数,如果为偶数,则模拟请求失败
bool isSuccess = (new Random().Next(0, 10)) % 2 == 0;
// ... ...模拟请求 HTTP
Thread.Sleep(TimeSpan.FromSeconds(2));
// 请求失败则重试
if (!isSuccess)
{
Console.WriteLine($"请求失败,count={count}");
new Thread(() =>
{
HttpRequest();
}).Start();
return;
}
// 完成一次任务,+1
Interlocked.Add(ref count,1);
Console.WriteLine($"完成任务,count={count}");
}
}
代码太糟糕了,但我们可以使用 CountdownEvent 类来改造它。
CountdownEvent 类
表示在计数变为零时处于有信号状态的同步基元。
也就是说,设定一个计数器,每个线程完成后,就会减去 1 ,当计数器为 0 时,代表所有线程都已经完成了任务。
构造函数和方法
CountdownEvent 类的构造函数如下:
| 构造函数 | 说明 |
|---|---|
| CountdownEvent(Int32) | 使用指定计数初始化 CountdownEvent 类的新实例。 |
CountdownEvent 类的常用方法如下:
| 方法 | 说明 |
|---|---|
| AddCount() | 将 CountdownEvent 的当前计数加 1。 |
| AddCount(Int32) | 将 CountdownEvent 的当前计数增加指定值。 |
| Reset() | 将 CurrentCount 重置为 InitialCount 的值。 |
| Reset(Int32) | 将 InitialCount 属性重新设置为指定值。 |
| Signal() | 向 CountdownEvent 注册信号,同时减小 CurrentCount 的值。 |
| Signal(Int32) | 向 CountdownEvent 注册多个信号,同时将 CurrentCount 的值减少指定数量。 |
| TryAddCount() | 增加一个 CurrentCount 的尝试。 |
| TryAddCount(Int32) | 增加指定值的 CurrentCount 的尝试。 |
| Wait() | 阻止当前线程,直到设置了 CountdownEvent 为止。 |
| Wait(CancellationToken) | 阻止当前线程,直到设置了 CountdownEvent 为止,同时观察 CancellationToken。 |
| Wait(Int32) | 阻止当前线程,直到设置了 CountdownEvent 为止,同时使用 32 位带符号整数测量超时。 |
| Wait(Int32, CancellationToken) | 阻止当前线程,直到设置了 CountdownEvent 为止,并使用 32 位带符号整数测量超时,同时观察 CancellationToken。 |
| Wait(TimeSpan) | 阻止当前线程,直到设置了 CountdownEvent 为止,同时使用 TimeSpan 测量超时。 |
| Wait(TimeSpan, CancellationToken) | 阻止当前线程,直到设置了 CountdownEvent 为止,并使用 TimeSpan 测量超时,同时观察 CancellationToken。 |
API 比较多,没事,我们来慢慢了解它。
示例
我们来编写一个场景代码,一个有五件事,需要完成,分别派出 5 个人去实现。
.Wait(); 用在一个线程中,这个线程将等待其它完成都完成任务后,才能继续往下执行。
Signal(); 用于工作线程中,向 CountdownEvent 对象发送信号,告知线程已经完成任务,然后 CountdownEvent.CurrentCount 将减去 1。
当计数器为 0 时,阻塞的线程将恢复执行。
代码示例如下:
class Program
{
// 手头上有 5 件事
private static CountdownEvent countd = new CountdownEvent(5);
static void Main(string[] args)
{
Console.WriteLine("开始交待任务");
// 同时叫 5 个人,去做 5 件事
for (int i = 0; i < 5; i++)
{
Thread thread = new Thread(DoOne);
thread.Name = $"{i}";
thread.Start();
}
// 等他们都完成事情
countd.Wait();
Console.WriteLine("任务完成,线程退出");
Console.ReadKey();
}
public static void DoOne()
{
int n = new Random().Next(0, 10);
// 模拟要 n 秒才能完成
Thread.Sleep(TimeSpan.FromSeconds(n));
// 完成了,减去一件事
countd.Signal();
Console.WriteLine($" {Thread.CurrentThread.Name}完成一件事了");
}
}
示例很简单,每个线程在完成自己的任务时,需要调用 Signal() 方法,使得计数器减去1。
.Wait(); 可以等待所有的任务完成。
需要注意的是,如果不调用 Signal() 或者计数器一直不为0,那么 Wait() 将无限等待。
当然,Wait() 可以设置等待时间,
另外我们也看到了常用方法中有 AddCount()、Reset()等。
这个类的等待控制方式比较宽松,Wait() 后,到底什么时候才能执行,全凭其它线程自觉。
如果发现线程执行任务失败,我们可以不调用 Signal() 或者 使用 AddCount() 来增加次数,进行重试
C#多线程(8):线程完成数的更多相关文章
- C#多线程之线程池篇1
在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...
- Java学习笔记-多线程-创建线程的方式
创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...
- Java多线程开发系列之四:玩转多线程(线程的控制1)
在前文中我们已经学习了:线程的基本情况.如何创建多线程.线程的生命周期.利用已有知识我们已经可以写出如何利用多线程处理大量任务这样简单的程序.但是当应用场景复杂时,我们还需要从管理控制入手,更好的操纵 ...
- iOS开发多线程篇—线程间的通信
iOS开发多线程篇—线程间的通信 一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任 ...
- 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法
[源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...
- .net学习之多线程、线程死锁、线程通信 生产者消费者模式、委托的简单使用、GDI(图形设计接口)常用的方法
1.多线程简单使用(1)进程是不执行代码的,执行代码的是线程,一个进程默认有一个线程(2)线程默认情况下都是前台线程,要所有的前台线程退出以后程序才会退出,进程里默认的线程我们叫做主线程或者叫做UI线 ...
- Java多线程之线程的同步
Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...
- Java多线程之线程的控制
Java多线程之线程的控制 线程中的7 种非常重要的状态: 初始New.可运行Runnable.运行Running.阻塞Blocked.锁池lock_pool.等待队列wait_pool.结束Dea ...
- 关于Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇高质量的博文)
Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文) 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享 ...
- Java多线程02(线程安全、线程同步、等待唤醒机制)
Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...
随机推荐
- 物联网浏览器(IoTBrowser)-Web串口自定义开发
物联网浏览器(IoTBrowser)-Web串口自定义开发 工控系统中绝大部分硬件使用串口通讯,不论是原始串口通讯协议还是基于串口的Modbus-RTU协议,在代码成面都是使用System.IO.Po ...
- 手写promise异步状态修改then方法返回来的结果
看看下面这一段代码返回来的是什么??? <body> <script type="text/javascript"> let p = new Promise ...
- 希尔伯特变换用于解调系统——以解调调频信号为例,FM Demodulation
What's The Hilbert Transform 简单地说,希尔伯特变换的物理意义为:把信号的所有频率分量的相位推迟90度,这样原信号和变换后信号可以视为一组IQ正交信号,在数字域正交化,可以 ...
- 找工作、备考、面试刷题网站推荐(牛客网、力扣、计蒜客、hihocoder、七月在线)以及acm竞赛oj
不管是找工作笔试面试白板试进大厂,还是研究生参加初试复试,数据结构和算法都是都是重中之重,刷题就很必要,来拿走自己的offer 吧! 一.offer刷题推荐 1.牛客网 链接:牛客网 - 找工作神器| ...
- java获取最近12个月月份
最近在做一个换电站管理的项目,其中有一个大屏折线图.要求计算近12个月的数据.所以,就需要写一个生成近12个月月份的算法.算法如下. 一:编写生成近12个月月份的算法 二:编写判断当天是否是月初的算法 ...
- 资深工程师 VSCode C/C++ 必备开发插件
1.前言 俗话说"工欲善其事,必先利其器",下面介绍几个VSCode提高开发效率的插件,资深工程师必备. 2.基础插件 2.1.Chinese(Simplified) vscode ...
- 24.3 向量化异常VEH--《Windows核心编程》
Windows 提供了向量化异常处理(vectored excepation handing,VEH)机制.程序可以注册一个函数,每当异常发送或者一个未处理异常脱离标准SEH的控制时,这个函数就会被调 ...
- Adoquery 简单的事务 编程 超级棒
1.记得 有一次 看 c#视频教程,发现了一个简单事务 处理的绝佳方法,就是 adoquery 其实是可以 同时执行多条 SQL 语句的, 当其中一条 SQL 语句失败了,那么其余 SQL 语句也会失 ...
- CentOS7环境源码安装python3.9
操作系统 : CentOS7.6.1810_x64 Python 版本 : 3.9.12 1.获取源代码 python官方网址: https://www.python.org/ 源码下载地址: 或者直 ...
- 了解一下基本的http代理配置
我们首先用一个简单例子了解一下基本的http代理配置 worker_processes 1; #nginx worker 数量 error_log logs/error.log; #指定错误日志文件路 ...