转:VC++线程同步-事件对象
这是整理孙鑫VC得到的关于线程同步方面的笔记.
n 事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
n 有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。得到事件对象后,因为是自动重置的事件对象,所以操作系统将该事件对象设置为非信号状态
//---------------------------------------------------以下手动重置事件对象不具有实际参考价值----------------------------------------------------------
#include <windows.h>
#include <iostream.h>
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
);
DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
);
int tickets=100;
HANDLE g_hEvent; //全局的句柄变量,用来保存所创建的事件对象的句柄。由于多个线程要访问g_hEvent这个对象,所以将其设置为全局变量。
void main()
{
HANDLE hThread1;
HANDLE hThread2;
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); //第三个状态为FALSE说明创建时事件初始化为无信号状态
/*(1)第二个参数设定TRUE为人工重置事件对象,当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。也就是说他们都可以同时运行。两个线程可以同时运行说明同步失败。ResetEvent(g_hEvent)手动把事件对象设置成非信号状态,人工重置必须显式的SetEvent设置有信号状态.(2)第二个参数设定FALSE为自动重置事件对象,当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程,同时将该事件对象设置为非信号状态。尽量不要用人工重置事件对象,因为会出现下面的问题
*/
SetEvent(g_hEvent);//把事件对象设置成有信号状态,但这时候所有的线程都变成有信号状态,所以每个线程前面需要用ResetEvent
Sleep(4000);
CloseHandle(g_hEvent);
}
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
// ResetEvent(g_hEvent); // 人工重置的事件对象,除非显示的调用ResetEvent(g_hEvent); 将事件对象设置为无信号状态,它将始终处于有信号状态
/*
在这用ResetEvent把护持对象设置成非信号状态是不可以的,因为它存在两个问题:
1)在单CPU的平台下,同一时刻只有一个线程能够运行。假设线程1先运行WaitForSingleObject(g_hEvent,INFINITE);它通过WaitForSingleObject(g_hEvent,INFINITE);得到了事件对象g_hEvent。但这个时候它的时间片终止了,轮到第二个线程运行。因为线程1的ResetEvent没有被执行,所有我们的事件对象仍然处于有信号状态。既然它是有信号状态,线程2就能得到我们这个事件。也就是我们这两个线程都进入了要保护的代码,当然结果是不可预料的。
2)在多CPU的平台下线程1和线程2可以同时运行。当它们请求到了事件对象后,你再将它们设为非信号状态已经不起作用了,因为它们已经进入到我们要保护的代码了。两个线程同时访问同一种资源当然结果是未知的。
*/
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket : "<<tickets--<<endl;
}
else
break;
SetEvent(g_hEvent); //将事件对象设置为有信号状态
}
return 0;
}
DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
// ResetEvent(g_hEvent);
/*
在这用ResetEvent把护持对象设置成非信号状态是不可以的,因为它存在两个问题:
1)在单CPU的平台下,同一时刻只有一个线程能够运行。假设线程1先运行WaitForSingleObject(g_hEvent,INFINITE);它通过WaitForSingleObject(g_hEvent,INFINITE);得到了事件对象g_hEvent。但这个时候它的时间片终止了,轮到第二个线程运行。因为线程1的ResetEvent没有被执行,所有我们的事件对象仍然处于有信号状态。既然它是有信号状态,线程2就能得到我们这个事件。也就是我们这两个线程都进入了要保护的代码,当然结果是不可预料的。
2)在多CPU的平台下线程1和线程2可以同时运行。当它们请求到了事件对象后,你再将它们设为非信号状态已经不起作用了,因为它们已经进入到我们要保护的代码了。两个线程同时访问同一种资源当然结果是未知的。
*/
if(tickets>0)
{
Sleep(1);
cout<<"thread2 sell ticket : "<<tickets--<<endl;
}
else
break;
SetEvent(g_hEvent);
}
return 0;
}
//---------------------------------------------------------------------------飘逸的分割线--------------------------------------------------------------------------
自动重置事件对象例子-----具有实用参考性
/*
自动重置事件对象,当事件对象为有信号状态的时候,等待该对象的线程只有一个能得到该事件对象,这时候系统会把他变成非信号状态,所以在这个线程运行结束之后,一定要用SetEvent把该事件对象重新设置成有信号状态
*/
#include <windows.h>
#include <iostream.h>
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
);
DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
);
int tickets=100;
HANDLE g_hEvent;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); //第二个参数设定FALSE为自动重置事件对象
SetEvent(g_hEvent); // 把事件对象设置成有信号状态,当然这里也可以通过把CreateEvent的第三个参数设置成TRUE来实现
Sleep(4000);
CloseHandle(g_hEvent);//关闭事件对象句柄
}
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE); // 这时候系统会把g_hEvent变成非信号状态
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket : "<<tickets--<<endl;
}
else
break;
SetEvent(g_hEvent);//重新设置成有信号状态
}
return 0;
}
DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
if(tickets>0)
{
Sleep(1);
cout<<"thread2 sell ticket : "<<tickets--<<endl;
}
else
break;
SetEvent(g_hEvent);
}
return 0;
}
转:VC++线程同步-事件对象的更多相关文章
- VC++ 线程同步 总结
注:所谓同步,并不是多个线程一起同时执行,而是他们协同步调,按预定的先后次序执行. 与线程相关的基本函数包括:CreateThread:创建线程CloseHandle:关闭线程句柄.注意,这只会使指定 ...
- 经典线程同步 事件Event
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题 ...
- 多线程面试题系列(6):经典线程同步 事件Event
上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的"线程所有权"特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题.首先 ...
- 转--- 秒杀多线程第六篇 经典线程同步 事件Event
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题 ...
- 秒杀多线程第六篇 经典线程同步 事件Event
原文地址:http://blog.csdn.net/morewindows/article/details/7445233 上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权” ...
- C#线程学习笔记五:线程同步--事件构造
本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html,记录一下学习过程以备后续查用. 前面讲的线 ...
- MFC线程(三):线程同步事件(event)与互斥(mutex)
前面讲了临界区可以用来达到线程同步.而事件(event)与互斥(mutex)也同样可以做到. Win32 API中的线程事件 HANDLE hEvent = NULL; void MainTestFu ...
- java线程同步以及对象锁和类锁解析(多线程synchronized关键字)
一.关于线程安全 1.是什么决定的线程安全问题? 线程安全问题基本是由全局变量及静态变量引起的. 若每个线程中对全局变量.静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的:若有多个线 ...
- VC++线程同步之临界区(CriticalSection)
1.相关文件和接口 #include <windows.h> CRITICAL_SECTION cs;//定义临界区对象 InitializeCriticalSection(&cs ...
随机推荐
- 求助关于jquery easyUI中的treegrid组件,请各位帮忙给个思路,谢谢啦
现在项目中用到jquery easyUI中的treegrid组件,已经可以正常显示了.但是在保存的时候遇到问题,页面上参照官网的例子可以在页面更新,但是怎么获取编辑后的数据进而保存到数据库呢?
- [Git] An efficient GIT workflow for mid/long term projects
reference : http://fle.github.io/an-efficient-git-workflow-for-midlong-term-projects.html Our full-w ...
- PhpSpreadsheet生成Excel时实现单元格自动换行
PhpSpreadsheet是PHPExcel的替代版本,PHPExcel的作者已经停止了更新,今天尝试了使用PhpSpreadsheet生成Excel的时候支持单元格内的自动换行,发现用法其实差不多 ...
- from __future__ import print_function
1.在python2.x的环境是使用下面语句,则第二句语法检查通过,第三句语法检查失败 from __future__ import print_function priint('good') pri ...
- 23.读写锁ReadWriteLock
ReentrantReadWriteLock 所谓的读写锁,是访问资源共享共享锁.互斥锁,如果对资源加了写锁,其他线程无法获取写锁与读锁,但是持有写锁的线程,可以对资源 加读锁:如果一 ...
- 【UOJ Round #8】
A 一道不错的题,虽然大家都觉得是水题,然而蒟蒻我想出来的好慢……Orz alpq 发现其实就是一个网格图,每一个大块都是同一颜色……横纵坐标互不干扰…… //UOJ Round #8 A #incl ...
- 数学图形之Breather surface
这是一种挺漂亮的曲面图形,可惜没有找到太多的相关解释. In differential equations, a breather surface is a mathematical surface ...
- Informatica 常用组件Source Qualifier之七 输入过滤器
通过输入源过滤器,可以降低 PowerCenter 查询的行数.如果在源过滤器中包括字符串 "WHERE" 或较大对象,PowerCenter 将使会话失败. 源限定符转换包括默 ...
- 第十六章 springboot + OKhttp + String.format
模拟浏览器向服务器发送请求四种方式: jdk原生的Http包下的一些类 httpclient(比较原始,不怎么用了):第一章 HttpClient的使用 Okhttp(好用,推荐) retrofit( ...
- 第一章 Java工具类目录
在这一系列博客中,主要是记录在实际开发中会常用的一些Java工具类,方便后续开发中使用. 以下的目录会随着后边具体工具类的添加而改变. 浮点数精确计算 第二章 Java浮点数精确计算 crc32将任意 ...