《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 ...
随机推荐
- Mongo分片基础命令
一.三节点作用 Shard: 用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障 Config Server: mon ...
- xtrabckup备份报错:Failed to connect to MySQL server: Can't connect to local MySQL server through socket '/data/mysql/mysql.sock' (2).
1.做软连接 [root@xxxxxx:/data/backup/log]# ln -s /var/lib/mysql/mysql.sock /tmp/mysql.sock [root@xxxxxxx ...
- python学习day4软件目录结构规范
为什么要设计好目录结构? 参考:http://www.cnblogs.com/alex3714/articles/5765046.html "设计项目目录结构",就和"代 ...
- 【POJ】2043.Area of Polygons
原题戳这里 开始一小段时间的POJ计算几何练习计划(估计很快就会被恶心回去) 题解 用一条平行于y轴的扫描线,计算两条扫描线之间多少格子被覆盖了 精度可tm变态了,可能是因为题目要求的关系吧,需要上取 ...
- tp5总结(三)
1.控制器 1-1.加载页面[使用系统函数eg:http://ww:7070/tp5-2/public/admin/test/load] 1-2.加载页面[继承控制器方法eg:http://ww:70 ...
- Linux下 rz 和 sz 命令的安装与使用
目录 Linux下 rz 和 sz 命令的安装与使用 rz/sz命令的安装 sz命令-发送文件到本地(下载): rz命令-本地上传文件到服务器(上传): 声明 Linux下 rz 和 sz 命令的安装 ...
- Bootstrap进阶一:Glyphicons 字体图标
基本组件是Bootstrap的精华之一,其中都是开发者平时需要用到的交互组件.例如:网站导航.标签页.工具条.面包屑.分页栏.提示标签.产品展示.提示信息块和进度条等.这些组件都配有jQuery插件, ...
- HTML Input 表单校验之datatype
凡要验证格式的元素均需绑定datatype属性,datatype可选值内置有10类,用来指定不同的验证格式. 如果还不能满足您的验证需求,可以传入自定义datatype,自定义datatype是一个非 ...
- printf的定义
1. printf的宏定义 #define XXX_ERROR 0#define XXX_WARNING 1#define XXX_INFO 2#define XXX_DEBUG 3#define X ...
- HashMap+双向链表手写LRU缓存算法/页面置换算法
import java.util.Hashtable; class DLinkedList { String key; //键 int value; //值 DLinkedList pre; //双向 ...