转: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 ...
随机推荐
- html 中怎么设置div的位置
利用CSS的position属性对元素定位,以下是position 属性规定元素的定位类型. absolute 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位.元素的位置通过 ...
- 如何重构"箭头型"代码
本文主要起因是,一次在微博上和朋友关于嵌套好几层的if-else语句的代码重构的讨论(微博原文),在微博上大家有各式各样的问题和想法.按道理来说这些都是编程的基本功,似乎不太值得写一篇文章,不过我觉得 ...
- ubuntu下用户的创建、修改
一.1.添加用户 (1)创建一个新的用户username #sudo useradd username (2)设置用户username 的密码 #sudo passwd username 2.添加用户 ...
- UVA 156 (13.08.04)
Ananagrams Most crossword puzzle fans are used to anagrams--groupsof words with the same letters i ...
- 简单使用CSS3实现炫酷读者墙效果
读者墙,在很多网站上都有,没有遇到过的,可以参考度娘:读者墙http://www.baidu.com/s?wd=%B6%C1%D5%DF%C7%BD 使用基础的Html和CSS写出雏形 需要一提的是头 ...
- js 获取读取cookie
// --- 设置cookie function setCookie(sName, sValue, expireHours) { var cookieString = sName + &quo ...
- IIS-设置session时间
session会话类型
- NGUI诡异的drawCall
看了很多关于NGUI drawCall的文章,见得比较多的一个观点是:一个 Atlas 对应一个Drawcall. 好奇心下做了个demo,两个panel中只用到一个Atlas,却产生了10个draw ...
- C++ vector用法(转)
在c++中,vector是一个十分有用的容器,下面对这个容器做一下总结. 1 基本操作 (1)头文件#include<vector>. (2)创建vector对象,vector<in ...
- @SuppressLint("NewApi")和@TargetApi()的区别
在Android代码中,我们有时会使用比我们在AndroidManifest中设置的android:minSdkVersion版本更高的方法,此时编译器会提示警告, 解决方法是在方法上加上@Suppr ...