先举一个有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核心编程》第九章——用内核对象进行线程同步的更多相关文章

  1. windows核心编程---第八章 使用内核对象进行线程同步

    使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...

  2. Windows核心编程:第9章 用内核对象进行线程同步

    Github https://github.com/gongluck/Windows-Core-Program.git //第9章 用内核对象进行线程同步.cpp: 定义应用程序的入口点. // #i ...

  3. Windows核心编程 第九章 线程与内核对象的同步(下)

    9.4 等待定时器内核对象 等待定时器是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象.它们通常用来在某个时间执行某个操作. 若要创建等待定时器,只需要调用C r e a t e Wa i ...

  4. Windows核心编程 第九章 线程与内核对象的同步(上)

    第9章 线程与内核对象的同步 上一章介绍了如何使用允许线程保留在用户方式中的机制来实现线程同步的方法.用户方式同步的优点是它的同步速度非常快.如果强调线程的运行速度,那么首先应该确定用户方式的线程同步 ...

  5. windows核心编程---第九章 同步设备IO与异步设备IO之同步IO

    同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...

  6. 第9章 用内核对象进行线程同步(4)_死锁(DeadLock)及其他

    9.7 线程同步对象速查表 对象 何时处于未触发状态 何时处于触发状态 成功等待的副作用 进程 进程仍在运行的时候 进程终止的时(ExitProcess.TerminateProcess) 没有 线程 ...

  7. 第9章 用内核对象进行线程同步(3)_信号量(semaphore)、互斥对象(mutex)

    9.5 信号量内核对象(Semaphore) (1)信号量的组成 ①计数器:该内核对象被使用的次数 ②最大资源数量:标识信号量可以控制的最大资源数量(带符号的32位) ③当前资源数量:标识当前可用资源 ...

  8. 第9章 用内核对象进行线程同步(2)_可等待计时器(WaitableTimer)

    9.4 可等待的计时器内核对象——某个指定的时间或每隔一段时间触发一次 (1)创建可等待计时器:CreateWaitableTimer(使用时应把常量_WIN32_WINNT定义为0x0400) 参数 ...

  9. 第9章 用内核对象进行线程同步(1)_事件对象(Event)

    9.1 等待函数 (1)WaitForSingleObject(hObject,dwMilliseonds); ①dwMilliseconds为INFINITE时表示无限等待 ②dwMilliseco ...

随机推荐

  1. 【LOJ】#2384. 「HNOI2013」切糕

    题解 神仙网络流啊-- naive的我一直想把每个纵轴拆点,每个纵轴建R个点(大概是要跑费用流吧--)--然后第二个限制就gg了,什么也想不出来,菜啊TAT 后来我发现大神们的建图都是,一个原点,一个 ...

  2. 【BZOJ】1152: [CTSC2006]歌唱王国Singleland

    题解 读错题了,是最后留下一个牛人首长歌颂他,和其他人没有关系,t就相当于数据组数 结论题,具体可看 https://www.zhihu.com/question/59895916/answer/19 ...

  3. 【POJ】2165.Gunman

    题解 把直线的斜率分解成二维,也就是随着z的增加x的增量和y的增量 我们发现一条合法直线向上移一点一定能碰到一条横线 知道了这条横线可以算出y的斜率 我们旋转一下,让这条横线碰到两条竖线,就可以算出x ...

  4. win7下docker环境搭建nginx+php-fpm+easyswoole开发环境

    基础的环境已在文章nginx.php-fpm.swoole HTTP/TCP压测对比中搭建了,现在是在这个基础上在搭建easyswoole开发环境 主要要修改的地方是dnmp包里面的docker-co ...

  5. poj3624 Charm Bracelet(DP,01背包)

    题目链接 http://poj.org/problem?id=3624 题意 有n个手镯,每个手镯有两个属性:重量W,需求因子D.还有一个背包,它能装下总重量不超过M的手镯.现在将一些镯子装入背包,求 ...

  6. jQuery 的运行机制(How jQuery Works)

    原文地址:http://learn.jquery.com/about-jquery/how-jquery-works/ linkjQuery: 基础知识 这是一个基本的教程,旨在帮助您开始使用jQue ...

  7. java的组合和继承

    其实我第一次学习java 的时候根本没有听说过组合这个名词,老师也更没有讲解过,我一直以为是我自己落掉了什么知识点,其实不是的,组合这个名词暂且把它定义为一个思维性的东西吧,相信读者都接触过了,但是并 ...

  8. DSP已经英雄迟暮了吗?FPGA才是未来的大杀器?

          DSP技术,在某些人看来,或者已经面临着英雄迟暮的感觉,就我们当前所知道的.Freesacle.ADI.NXP早就停掉了新技术发展,而当前从大的方面说只剩下TI一家扛着Digital Si ...

  9. 安恒月赛WP

    一月 一叶飘零大佬的WP:安恒月赛一月 二进制部分:zjgcjy大佬的WP reverse1更容易理解的一种解法 pwn1详解 二月 一叶飘零WP 二进制部分: reverse Pwn 三月 ...

  10. Web2.0应用程序的7条原则

    个人看好Web的发展潜力,本文字摘自<Collective Intelligence 实战> 网络是平台 使用传统许可模式软件的公司或用户必须运行软件.定期更新至最新版本,以及扩展它来满足 ...