C++多线程同步技巧(二)--- 事件
简介
Windows在线程控制方面提供了多种信号处理机制,其中一种便是使用 CreateEvent() 函数创建事件,然后使用信号控制线程运行。其中将事件变为有信号可使用 SetEvent() 函数,将事件信号复位(变为无信号)可使用 ResetEvent() 函数,信号可以配合 WaitForSingleObject() 函数对线程的同步进行控制,当有信号时,此函数便会放行;无信号时,此函数会将阻塞。
提示: CreateEvent() 函数的参数 bManualReset 的含义是信号是否由人工复位,如果选择true,则信号必须手动采用ResetEvent() 函数进行复位操作。在这种情况下,可能会偶尔出现线程不同步的情况,问题出在可能同时会有多个线程穿过 WaitForSingleObject() 函数,导致复位失效,所以在这种情况下,为确保万无一失,我们一般会再添加一个限制条件,例如临界区或互斥体;如果选择的是false,则当一个信号经过 WaitForSingleObject() 函数的时候,函数会自动将事件信号复位。
代码样例
- bManualReset参数为 false
////////////////////////////////
//
// FileName : ThreadEventDemo.cpp
// Creator : PeterZheng
// Date : 2018/9/23 18:00
// Comment : The usage of "CreateEvent"
//
////////////////////////////////
#pragma once
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
DWORD WINAPI func1(LPVOID lpParam);
DWORD WINAPI func2(LPVOID lpParam);
HANDLE hEvent = NULL;
unsigned int unCount = 0;
DWORD WINAPI func1(LPVOID lpParam)
{
while (true)
{
WaitForSingleObject(hEvent, INFINITE);
if (unCount < 100)
{
unCount++;
Sleep(10);
cout << "Count: " << unCount << endl;
SetEvent(hEvent);
continue;
}
// 因为WaitForSingleObject函数会自动复位,可能导致另外一个线程始终等待不到信号,造成“假死”现象,所以这里需要使用SetEvent重置信号。
SetEvent(hEvent);
break;
}
return 0;
}
DWORD WINAPI func2(LPVOID lpParam)
{
while (true)
{
WaitForSingleObject(hEvent, INFINITE);
if (unCount < 100)
{
unCount++;
Sleep(10);
cout << "Count: " << unCount << endl;
SetEvent(hEvent); // 设置事件为有信号状态
continue;
}
SetEvent(hEvent);
break;
}
return 0;
}
int main(void)
{
HANDLE hThread[2] = { NULL };
hEvent = CreateEvent(NULL, false, false, NULL); //创建一个匿名事件,当参数bManualReset设置为false时
hThread[0] = CreateThread(NULL, 0, func1, NULL, 0, NULL);
cout << "Thread-1 is RUNNING" << endl;
hThread[1] = CreateThread(NULL, 0, func2, NULL, 0, NULL);
cout << "Thread-2 is RUNNING" << endl;
SetEvent(hEvent);
WaitForMultipleObjects(2, hThread, true, INFINITE); //等待两个线程运行结束
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(hEvent);
system("pause");
return 0;
}
- bManualReset参数为 true
////////////////////////////////
//
// FileName : ThreadEventDemo.cpp
// Creator : PeterZheng
// Date : 2018/9/23 18:00
// Comment : The usage of "CreateEvent"
//
////////////////////////////////
#pragma once
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
DWORD WINAPI func1(LPVOID lpParam);
DWORD WINAPI func2(LPVOID lpParam);
HANDLE hEvent = NULL;
HANDLE hMutex = NULL;
unsigned int unCount = 0;
DWORD WINAPI func1(LPVOID lpParam)
{
while (true)
{
WaitForSingleObject(hEvent, INFINITE);
WaitForSingleObject(hMutex, INFINITE); //为互斥体上锁
ResetEvent(hEvent); // 重置事件为无信号状态
if (unCount < 100)
{
unCount++;
Sleep(10);
cout << "Count: " << unCount << endl;
SetEvent(hEvent); // 设置事件为有信号状态
ReleaseMutex(hMutex); //互斥体解锁
}
else
{
SetEvent(hEvent);
ReleaseMutex(hMutex);
break;
}
}
return 0;
}
DWORD WINAPI func2(LPVOID lpParam)
{
while (true)
{
WaitForSingleObject(hEvent, INFINITE);
WaitForSingleObject(hMutex, INFINITE); //为互斥体上锁
ResetEvent(hEvent); // 重置事件为无信号状态
if (unCount < 100)
{
unCount++;
Sleep(10);
cout << "Count: " << unCount << endl;
SetEvent(hEvent); // 设置事件为有信号状态
ReleaseMutex(hMutex);
}
else
{
SetEvent(hEvent);
ReleaseMutex(hMutex);
break;
}
}
return 0;
}
int main(void)
{
HANDLE hThread[2] = { NULL };
hEvent = CreateEvent(NULL, true, false, NULL); //创建一个匿名事件,当参数bManualReset设置为true时
hMutex = CreateMutex(NULL, false, NULL); //创建一个匿名互斥体
hThread[0] = CreateThread(NULL, 0, func1, NULL, 0, NULL);
cout << "Thread-1 is RUNNING" << endl;
hThread[1] = CreateThread(NULL, 0, func2, NULL, 0, NULL);
cout << "Thread-2 is RUNNING" << endl;
SetEvent(hEvent); // 设置事件为有信号状态
WaitForMultipleObjects(2, hThread, true, INFINITE); //等待两个线程运行结束
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(hEvent);
CloseHandle(hMutex);
system("pause");
return 0;
}
参考文档
【1】https://blog.csdn.net/s_lisheng/article/details/74278765
C++多线程同步技巧(二)--- 事件的更多相关文章
- Windows多线程同步系列之三-----事件对象
事件是一个内核事件,内核事件是什么呢,我理解也不深入也不好说,暂且理解为一个内核维护的数据类型吧通过内核事件同步主要 的方法是对事件的信号有和无来进行同步. 比如当我们一个线程进入一段临界代码(独占代 ...
- C++多线程同步技巧(四)--- 信号量
简介 信号量是维护0到指定最大值之间的同步对象.信号量状态在其计数大于0时是有信号的,而其计数是0时是无信号的.信号量对象在控制上可以支持有限数量共享资源的访问,可以用于线程同步,预防死锁等领域. 信 ...
- C++多线程同步技巧(三)--- 互斥体
简介 Windows互斥对象机制. 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问,在线程同步与保证程序单体运行上都有相当大的用处. 代码 ...
- C++多线程同步技巧(一) --- 临界区
简介 C++中关于多线程的内容对于构建工程来说是至关重要的,C++本身也对关于多线程的操作提供了很好的支持.本章笔者就来介绍一下C++有关于多线程的重要知识点---临界区. 临界区的作用 线程就像是进 ...
- [一个经典的多线程同步问题]解决方案二:Event事件
使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权”特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题. 首先介绍下如何使用事件.事件E ...
- C#多线程同步事件及等待句柄AutoResetEvent 和 ManualResetEvent
最近捣鼓了一下多线程的同步问题,发现其实C#关于多线程同步事件处理还是很灵活,这里主要写一下,自己测试的一些代码,涉及到了AutoResetEvent 和 ManualResetEvent,当然还有也 ...
- Windows多线程同步系列之二-----关键区
关键区对象为:CRITICAL_SECTION 当某个线程进入关键区之后,其他线程将阻塞等待,知道该线程释放关键区的拥有权. 关键区同步主要有以下几个API 初始化关键区对象,无返回值,传入一个关键区 ...
- java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)
本篇我们将讨论以下知识点: 1.线程同步问题的产生 什么是线程同步问题,我们先来看一段卖票系统的代码,然后再分析这个问题: package com.zejian.test; /** * @author ...
- java多线程同步机制
一.关键字: thread(线程).thread-safe(线程安全).intercurrent(并发的) synchronized(同步的).asynchronized(异步的). volatile ...
随机推荐
- [转]Laravel - Where null and Where not null eloquent query example
本文转自: https://hdtuto.com/article/laravel-where-null-and-where-not-null-eloquent-query-example- if yo ...
- [转]ERROR: http://rancherserver/v1 is not accessible
本文转自:http://securityer.lofter.com/post/1d0f3ee7_10c465cc 安装rancher agent时出现以下报错 [root@localhost ~]# ...
- npm 安装 卸载 模块(转载)
来源 https://blog.csdn.net/yihanzhi/article/details/75665959 利用npm 安装删除模块 npm安装模块 [npm install xxx]利用 ...
- Netty 系列三(ByteBuf).
一.概述和原理 网络数据传输的基本单位总是字节,Netty 提供了 ByteBuf 作为它的字节容器,既解决了 JDK API 的局限性,又为网络应用程序提供了更好的 API,ByteBuf 的优点: ...
- Springboot整合Websocket遇到的坑
Springboot整合Websocket遇到的坑 一.使用Springboot内嵌的tomcat启动websocket 1.添加ServerEndpointExporter配置bean @Confi ...
- 百度前端学院-基础学院-第七天到第八天之BFC
1.BFC简介 BFC全称"block formatting context",中文为“块级格式化上下文”.特征总之记住一句话: BFC元素特征表现原则就是:内部元素无论怎么翻江倒 ...
- 精心收集的 48 个 JavaScript 代码片段,仅需 30 秒就可理解!
原文:https://github.com/Chalarangelo/30-seconds-of-code#anagrams-of-string-with-duplicates 作者:Chalaran ...
- js替换字符中的斜杠反斜杠
var reg=/\\|\//g; var a="a\a\\a/b" alert(a.replace(reg,"-"));
- iphone屏幕镜像 屏幕镜像怎么用
iPhone手机投屏到电脑设备上,需要使用到AirPlay镜像功能,但是有些苹果新用户朋友一定还不知道iphone屏幕镜像怎么用吧?你要着急下面为你提供解决方法. 使用工具:iphone.电脑 操作方 ...
- Android为TV端助力 转载:内存泄露与内存溢出的区别
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory:比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出. ...