《Windows核心编程》第九章——用内核对象进行线程同步
先举一个有bug的例子:
#include <iostream>
#include <windows.h>
#include <process.h> using namespace std;
#define MAX_SIZE 0x500 HANDLE g_hSubmit;
HANDLE g_hReturn;
HANDLE g_hStop;
char g_szInput[MAX_SIZE] = {}; unsigned int _stdcall ThreadServer(void* pParam)
{
while (TRUE)
{
int nWaitRes = WaitForSingleObject(g_hStop, 100);
if (WAIT_OBJECT_0 == nWaitRes)
break; WaitForSingleObject(g_hSubmit, INFINITE);
printf("Recieve:%s\n", g_szInput);
SetEvent(g_hReturn);
}
SetEvent(g_hStop);
printf("Set stop\n");
return ;
} void main()
{
int count = ;
g_hSubmit = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hReturn = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hStop = CreateEvent(NULL, FALSE, FALSE, NULL); HANDLE hTheadServer = (HANDLE)_beginthreadex(NULL, , ThreadServer, NULL, , NULL);
while (TRUE)
{
count++;
printf("Input:");
cin.getline(g_szInput, MAX_SIZE);
SetEvent(g_hSubmit);
WaitForSingleObject(g_hReturn, INFINITE);
if (count == ){
Sleep();
SetEvent(g_hStop); break;
}
} HANDLE hHandle[];
hHandle[] = g_hStop;
hHandle[] = hTheadServer;
WaitForMultipleObjects(, hHandle, TRUE, INFINITE);
CloseHandle(hTheadServer);
CloseHandle(g_hReturn);
CloseHandle(g_hStop);
CloseHandle(g_hSubmit);
getchar(); }
起初,我想要设置一个事件——g_hStop来通知线程,使得ThreadServer线程能够被主线程停止,但是这里出现了一个问题,如果我刻意让主线程Sleep2秒再去SetEvent,那么等待g_hStop的wait函数就会超时,从而往下继续执行等待Input,而此时主线程已经退出input循环,那么就会死锁。所以我改为使用全局变量来使得Threadserver线程退出:
#include <iostream>
#include <windows.h>
#include <process.h> using namespace std;
#define MAX_SIZE 0x500 HANDLE g_hSubmit;
HANDLE g_hReturn;
HANDLE g_hStop;
int g_nCount = ;
char g_szInput[MAX_SIZE] = {}; unsigned int _stdcall ThreadServer(void* pParam)
{
while (TRUE)
{
if (g_nCount == )
break; WaitForSingleObject(g_hSubmit, INFINITE);
printf("Recieve:%s\n", g_szInput);
SetEvent(g_hReturn);
}
SetEvent(g_hStop);
printf("Set stop\n");
return ;
} void main()
{
g_hSubmit = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hReturn = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hStop = CreateEvent(NULL, FALSE, FALSE, NULL); HANDLE hTheadServer = (HANDLE)_beginthreadex(NULL, , ThreadServer, NULL, , NULL);
while (TRUE)
{
g_nCount++;
printf("Input:");
cin.getline(g_szInput, MAX_SIZE);
SetEvent(g_hSubmit);
WaitForSingleObject(g_hReturn, INFINITE);
if (g_nCount == ){
Sleep();
SetEvent(g_hStop); break;
}
} HANDLE hHandle[];
hHandle[] = g_hStop;
hHandle[] = hTheadServer;
WaitForMultipleObjects(, hHandle, TRUE, INFINITE);
CloseHandle(hTheadServer);
CloseHandle(g_hReturn);
CloseHandle(g_hSubmit);
getchar(); }
三种方式改进:
1、如果你非要使用第一种情况,那么请把等待时间设置的长一些,不要是100毫秒,起码要是等待十秒,确保事件触发后,不会超时。
2、在代码设计的时候,就不要在while中使用两个waitforsingleobject,这种设计就给死锁带来了可能性:
3、使用waitformultiobject等待两个event之一,然后判断等到的是哪个,从而决定来做什么
一个Mutex和semaphore合用的例子:
#include <iostream>
#include <windows.h>
#include <vector>
#include <process.h> using namespace std; #define MAX_SIZE 10 long g_ServerCount = ; class CQueue{
public:
CQueue();
~CQueue(); void Append();
void Remove();
private:
vector<int> m_vecQueue;
HANDLE m_hMutex;
HANDLE m_hSem;
HANDLE m_hHandles[];
}; CQueue g_c; CQueue::CQueue()
{
m_hMutex = CreateMutex(NULL, FALSE, NULL);
m_hSem = CreateSemaphore(NULL, , , NULL);
m_hHandles[] = m_hMutex;
m_hHandles[] = m_hSem;
} CQueue::~CQueue()
{
CloseHandle(m_hMutex);
CloseHandle(m_hSem);
} void CQueue::Append(){
DWORD dwRet = WaitForSingleObject(m_hMutex, INFINITE);
InterlockedExchangeAdd(&g_ServerCount, );
if (dwRet == WAIT_OBJECT_0)
{
LONG lPrevCount;
int bRet = ReleaseSemaphore(m_hSem, , &lPrevCount);
if (bRet)
{
m_vecQueue.push_back(g_ServerCount);
printf("Add element %d\n", g_ServerCount);
}
}
ReleaseMutex(m_hMutex);
} void CQueue::Remove()
{
DWORD dwRet = WaitForMultipleObjects(, m_hHandles, TRUE, INFINITE);
if (WAIT_OBJECT_0 == dwRet)
{
printf("Remove element %d\n", m_vecQueue.back());
m_vecQueue.pop_back();
}
ReleaseMutex(m_hMutex);
} unsigned int _stdcall ServerThread(void* pParam)
{
while (TRUE)
{
Sleep();
g_c.Append();
} return ;
} unsigned int _stdcall ClientThread(void* pParam)
{
while (TRUE)
{
Sleep();
g_c.Remove();
} return ;
} void main()
{
HANDLE h_Handles[];
h_Handles[] = (HANDLE)_beginthreadex(NULL, , ServerThread, NULL, , NULL);
h_Handles[] = (HANDLE)_beginthreadex(NULL, , ServerThread, NULL, , NULL);
h_Handles[] = (HANDLE)_beginthreadex(NULL, , ClientThread, NULL, , NULL);
WaitForMultipleObjects(_countof(h_Handles), h_Handles, TRUE, INFINITE);
for (int i = ; i < _countof(h_Handles); i++)
CloseHandle(h_Handles[i]);
getchar();
}
《Windows核心编程》第九章——用内核对象进行线程同步的更多相关文章
- windows核心编程---第八章 使用内核对象进行线程同步
使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...
- Windows核心编程:第9章 用内核对象进行线程同步
Github https://github.com/gongluck/Windows-Core-Program.git //第9章 用内核对象进行线程同步.cpp: 定义应用程序的入口点. // #i ...
- Windows核心编程 第九章 线程与内核对象的同步(下)
9.4 等待定时器内核对象 等待定时器是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象.它们通常用来在某个时间执行某个操作. 若要创建等待定时器,只需要调用C r e a t e Wa i ...
- Windows核心编程 第九章 线程与内核对象的同步(上)
第9章 线程与内核对象的同步 上一章介绍了如何使用允许线程保留在用户方式中的机制来实现线程同步的方法.用户方式同步的优点是它的同步速度非常快.如果强调线程的运行速度,那么首先应该确定用户方式的线程同步 ...
- windows核心编程---第九章 同步设备IO与异步设备IO之同步IO
同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...
- 第9章 用内核对象进行线程同步(4)_死锁(DeadLock)及其他
9.7 线程同步对象速查表 对象 何时处于未触发状态 何时处于触发状态 成功等待的副作用 进程 进程仍在运行的时候 进程终止的时(ExitProcess.TerminateProcess) 没有 线程 ...
- 第9章 用内核对象进行线程同步(3)_信号量(semaphore)、互斥对象(mutex)
9.5 信号量内核对象(Semaphore) (1)信号量的组成 ①计数器:该内核对象被使用的次数 ②最大资源数量:标识信号量可以控制的最大资源数量(带符号的32位) ③当前资源数量:标识当前可用资源 ...
- 第9章 用内核对象进行线程同步(2)_可等待计时器(WaitableTimer)
9.4 可等待的计时器内核对象——某个指定的时间或每隔一段时间触发一次 (1)创建可等待计时器:CreateWaitableTimer(使用时应把常量_WIN32_WINNT定义为0x0400) 参数 ...
- 第9章 用内核对象进行线程同步(1)_事件对象(Event)
9.1 等待函数 (1)WaitForSingleObject(hObject,dwMilliseonds); ①dwMilliseconds为INFINITE时表示无限等待 ②dwMilliseco ...
随机推荐
- Hive(十)Hive性能调优总结
一.Fetch抓取 1.理论分析 Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算.例如:SELECT * FROM employees;在这种情况下,Hive可以简单 ...
- python实现获取系统版本和mac信息上传到指定接口
import os,platform,uuid,urllib.parse,urllib.request,json def BeforeSystemRequests(): ''' the systemi ...
- 【51nod】1312 最大异或和
题解 很显然我们求出一组线性基来,如果有M个基,那么可以构造N - M + 1个最大异或值 而对于线性基中的元素,除了最大的元素,我们用最大异或值异或掉每个元素累加进答案 而不是把线性基中的元素处理成 ...
- jsp页面中注释 <!-- --> 和<%-- --%> 的区别
jsp页面中注释 <!-- --> 和<%-- --%> 的区别 原创 2016年09月01日 17:55:44 标签: jsp注释 5605 今天发现一个问题:在jsp代码中 ...
- Git配置用户名密码
配置Git 在Linux下和windows下配置Git的方法差不多,只是在Linux下,可以在命令行里直接使用git config进行配置, 而在windows下则要先打开“Git Bash”,进入m ...
- MYSQL插入不能中文的问题的解决
这个问题是由于数据库的字符集不对的问题. 解决方法: 打开要用的数据库,输入命令 status 如果Client characterset 值为utf8,则要改为:set char set 'gbk' ...
- 链路跟踪技术traceId的总结和实践
目录 写作背景 什么是链路跟踪 目前常见的链路跟踪技术及其优缺点 链路跟踪技术的实现原理 代码示例 背景 由于最近系统上线后,访问量达,出现线上问题后往往无从下手排查,即使打印了很多日志,依然无法快速 ...
- ASP.NET MVC 提高运行速度的几种性能优化方法
主要介绍ASP.NETMVC 应用提速的六种方法,因为没有人喜欢等待,所以介绍几种常用的优化方法. 大家可能会遇到排队等待,遇到红灯要等待,开个网页要等待,等等等. 理所当然,没有人喜欢等待网页慢吞吞 ...
- Swift2.0语言教程之类的方法
Swift2.0语言教程之类的方法 Swift2.0语言的方法 方法其实就是函数,只不过它被定义在了类中.在Swift中,根据被使用的方式不同,方法分为了实例方法和类型方法两种.这两种方法的定义也和O ...
- PHP渗透中的奇淫技巧--检查相等时的漏洞
PHP是现在网站中最为常用的后端语言之一,是一种类型系统 动态.弱类型的面向对象式编程语言.可以嵌入HTML文本中,是目前最流行的web后端语言之一,并且可以和Web Server 如apache和n ...