- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
上文 编码技巧 --- 同步锁对象的选定 中,提到了在C#中,让线程同步有两种方式:
加锁是最常用的线程同步的方法,就不再讨论,本篇主要讨论使用信号量同步线程.
实际上,再C#中 EventWaitHandle 、 Semaphore 、 Mutex 都是抽象类 WaitHandle 的派生类,它提供了一组等待信号的方法和属性。如下图:
主要包含静态方法 SignalAndWait() , WaitAll() , WaitAny() 及一个虚方法 WaitOne() 。下面介绍一个这几个方法.
介绍这些方法之前,先简单介绍一下 WaitHandle 的派生类 EventWaitHandle ,该派生类有两个实现类 AutoResetEvent 和 ManualResetEvent ,其方法列表如下:
重点说一下, Set() 和 Reset()
Set()
时,它将被设置为终止状态,并允许一个或多个等待该事件的线程继续执行。 Reset()
时,它将被设置为非终止状态,所有想要等待该事件的线程都将被阻塞,直到调用 Set()
方法使其变为终止状态。 注意:这里的有信号,无信号的意思类似于红绿灯,有信号你才能够通行,对于线程来说,有信号意味着可以接着往下运行,无信号则阻塞等待信号.
接下来的代码段演示皆使用 AutoResetEvent 进行演示.
当调用 WaitHandle 的静态方法 SignalAndWait() 时,会使得当前线程等待一个 WaitHandle 对象的信号,同时设置另一个 WaitHandle 对象为有信号状态。当第一个 WaitHandle 对象收到信号时,当前线程继续执行,同时第二个 WaitHandle 对象变为无信号状态.
static AutoResetEvent event1 = new AutoResetEvent(false);
static AutoResetEvent event2 = new AutoResetEvent(false);
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(Worker1));
Thread t2 = new Thread(new ThreadStart(Worker2));
t1.Start();
t2.Start();
Console.ReadLine();
}
static void Worker1()
{
Console.WriteLine("线程1开始执行……");
event1.WaitOne(); // 等待事件1的发生
Console.WriteLine("线程1收到事件1的信号,继续执行……");
WaitHandle.SignalAndWait(event1, event2); // 发送事件2的信号并等待事件2的发生
Console.WriteLine("线程1收到事件2的信号,继续执行……");
}
static void Worker2()
{
Console.WriteLine("线程2开始执行……");
Thread.Sleep(2000); // 模拟线程2的执行时间
Console.WriteLine("线程2发出事件1的信号……");
event1.Set(); // 发送事件1的信号
Thread.Sleep(2000); // 模拟线程2的执行时间
Console.WriteLine("线程2发出事件2的信号……");
WaitHandle.SignalAndWait(event2, event1); // 发送事件1的信号并等待事件1的发生
Console.WriteLine("线程2收到事件1的信号,继续执行……");
}
输出:
线程1开始执行……
线程2开始执行……
线程2发出事件1的信号……
线程1收到事件1的信号,继续执行……
线程2发出事件2的信号……
线程2收到事件1的信号,继续执行……
线程1收到事件2的信号,继续执行……
当调用 WaitHandle 的静态方法 WaitAll() 时,它可以等待多个WaitHandle对象的信号,直到所有对象都收到信号或等待超时.
static AutoResetEvent[] events = new AutoResetEvent[3]
{
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false)
};
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(Worker1));
Thread t2 = new Thread(new ThreadStart(Worker2));
t1.Start();
t2.Start();
Console.ReadLine();
}
static void Worker1()
{
Console.WriteLine("线程1开始执行……");
WaitHandle.WaitAll(events); // 等待所有事件的发生
Console.WriteLine("线程1收到所有事件的信号,继续执行……");
}
static void Worker2()
{
Console.WriteLine("线程2开始执行……");
Thread.Sleep(2000); // 模拟线程2的执行时间
Console.WriteLine("线程2发出事件1的信号……");
events[0].Set(); // 发送事件1的信号
Thread.Sleep(2000); // 模拟线程2的执行时间
Console.WriteLine("线程2发出事件2的信号……");
events[1].Set(); // 发送事件2的信号
Thread.Sleep(2000); // 模拟线程2的执行时间
Console.WriteLine("线程2发出事件3的信号……");
events[2].Set(); // 发送事件3的信号
}
输出:
线程1开始执行……
线程2开始执行……
线程2发出事件1的信号……
线程2发出事件2的信号……
线程2发出事件3的信号……
线程1收到所有事件的信号,继续执行……
当调用 WaitHandle 的静态方法 WaitAny() 时,它可以等待多个WaitHandle对象中的任意一个对象收到信号,直到有一个对象收到信号或等待超时.
static AutoResetEvent[] events = new AutoResetEvent[3]
{
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false)
};
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(Worker1));
Thread t2 = new Thread(new ThreadStart(Worker2));
t1.Start();
t2.Start();
Console.ReadLine();
}
static void Worker1()
{
Console.WriteLine("线程1开始执行……");
WaitHandle.WaitAny(events); // 等待任意事件的发生
Console.WriteLine("线程1收到任意事件的信号,继续执行……");
}
static void Worker2()
{
Console.WriteLine("线程2开始执行……");
var randomIndex = new Random().Next(0, 2);
Console.WriteLine("线程2发出任意一个事件的信号……");
events[randomIndex].Set(); //发送任意一个事件的信号
}
输出:
线程1开始执行……
线程2开始执行……
线程2发出任意一个事件的信号……
线程1收到任意事件的信号,继续执行……
WaitOne() 方法上文中其实已经用到了,它就表示阻塞当前线程,等待当前 WaitHandle 对象收到信号,直到对象收到信号或等待超时。如果WaitHandle对象收到信号,WaitOne()方法返回true,否则返回false。使用简单就不在贴代码段.
上面已经提到了 EventWaitHandle 、 Semaphore 、 Mutex 都是抽象类 WaitHandle 的派生类,它们的作用类似,但在使用和实现上有一些不同。下面我们来简单介绍下它们的异同点.
EventWaitHandle:
EventWaitHandle 有两种类型: AutoResetEvent 和 ManualResetEvent 。它们的区别在于 AutoResetEvent 在有信号时只通知一个等待线程,而 ManualResetEvent 在有信号时通知所有等待线程。 两者设置为终止状态的方式都是调用 Set() 方法.
Semaphore 。
Semaphore 可以用于多个线程之间的资源控制。 Semaphore 可以控制同时访问共享资源的线程数量。设置为终止状态的方式是调用 Release() 方法.
Mutex 。
Mutex 可以用于多个线程之间的互斥访问共享资源。 Mutex 可以保证同一时间只有一个线程可以访问共享资源。设置为终止状态的方式是调用 ReleaseMutex() 方法.
最后此篇关于并发编程---信号量线程同步的文章就讲到这里了,如果你想了解更多关于并发编程---信号量线程同步的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试打印 timeval 类型的值。实际上我可以打印它,但我收到以下警告: 该行有多个标记 格式“%ld”需要“long int”类型,但参数 2 的类型为“struct timeval” 程序
我正在编写自己的 unix 终端,但在执行命令时遇到问题: 首先,我获取用户输入并将其存储到缓冲区中,然后我将单词分开并将它们存储到我的 argv[] 数组中。IE命令是“firefox”以启动存储在
我是 CUDA 的新手。我有一个关于一个简单程序的问题,希望有人能注意到我的错误。 __global__ void ADD(float* A, float* B, float* C) { con
我有一个关于 C 语言 CGI 编程的一般性问题。 我使用嵌入式 Web 服务器来处理 Web 界面。为此,我在服务器中存储了一个 HTML 文件。在此 HTML 文件中包含 JavaScript 和
**摘要:**在代码的世界中,是存在很多艺术般的写法,这可能也是部分程序员追求编程这项事业的内在动力。 本文分享自华为云社区《【云驻共创】用4种代码中的艺术试图唤回你对编程的兴趣》,作者: break
我有一个函数,它的任务是在父对象中创建一个变量。我想要的是让函数在调用它的级别创建变量。 createVariable testFunc() [1] "test" > testFunc2() [1]
以下代码用于将多个连续的空格替换为1个空格。虽然我设法做到了,但我对花括号的使用感到困惑。 这个实际上运行良好: #include #include int main() { int ch, la
我正在尝试将文件写入磁盘,然后自动重新编译。不幸的是,某事似乎不起作用,我收到一条我还不明白的错误消息(我是 C 初学者 :-)。如果我手动编译生成的 hello.c,一切正常吗?! #include
如何将指针值传递给结构数组; 例如,在 txt 上我有这个: John Doe;xxxx@hotmail.com;214425532; 我的代码: typedef struct Person{
我尝试编写一些代码来检索 objectID,结果是 2B-06-01-04-01-82-31-01-03-01-01 . 这个值不正确吗? // Send a SysObjectId SNMP req
您好,提前感谢您的帮助, (请注意评论部分以获得更多见解:即,以下示例中的成本列已添加到此问题中;西蒙提供了一个很好的答案,但成本列本身并未出现在他的数据响应中,尽管他提供的功能与成本列一起使用) 我
我想知道是否有人能够提出一些解决非线性优化问题的软件包的方法,而非线性优化问题可以为优化解决方案提供整数变量?问题是使具有相等约束的函数最小化,该函数受某些上下边界约束的约束。 我已经在R中使用了'n
我是 R 编程的初学者,正在尝试向具有 50 列的矩阵添加一个额外的列。这个新列将是该行中前 10 个值的平均值。 randomMatrix <- generateMatrix(1,5000,100,
我在《K&R II C 编程 ANSI C》一书中读到,“>>”和“0; nwords--) sum += *buf++; sum = (sum >>
当下拉列表的选择发生变化时,我想: 1) 通过 div 在整个网站上显示一些 GUI 阻止覆盖 2)然后处理一些代码 3) 然后隐藏叠加层。 问题是,当我在事件监听器函数中编写此逻辑时,将执行 onC
我正在使用 Clojure 和 RESTEasy 设计 JAX-RS REST 服务器. 据我了解,用 Lisp 系列语言编写的应用程序比用“传统”命令式语言编写的应用程序更多地构建为“特定于领域的语
我目前正在研究一种替代出勤监控系统作为一项举措。目前,我设计的用户表单如下所示: Time Stamp Userform 它的工作原理如下: 员工将选择他/她将使用的时间戳类型:开始时间、超时、第一次
我是一名学生,试图自学编程,从在线资源和像您这样的人那里获得帮助。我在网上找到了一个练习来创建一个小程序来执行此操作: 编写一个程序,读取数字 a 和 b(长整型)并列出 a 和 b 之间有多少个数字
我正在尝试编写一个 shell 程序,给定一个参数,打印程序的名称和参数中的每个奇数词(即,不是偶数词)。但是,我没有得到预期的结果。在跟踪我的程序时,我注意到,尽管奇数词(例如,第 5 个词,5 %
只是想知道是否有任何 Java API 可以让您控制台式机/笔记本电脑外壳上的 LED? 或者,如果不可能,是否有可能? 最佳答案 如果你说的是前面的 LED 指示电源状态和 HDD 繁忙状态,恐怕没
我是一名优秀的程序员,十分优秀!