转: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 ...
随机推荐
- java中初始化对象变量的方法
1.在类定义对象的地方初始化 2.在类构造器中初始化 3.在正要使用这些对象之前,惰性初始化,或者叫惰性载入 4.使用实例初始化 在方法里使用初始化
- java获取路径(转)
1.利用System.getProperty()函数获取当前路径:System.out.println(System.getProperty("user.dir"));//user ...
- Excel向上取整
CEILING函数语法:CEILING(number,significance)
- 手机网站和PC网站兼容的响应式网页设计
今天跟大家介绍的这个网站叫 媒体查询 官网域名:http://mediaqueri.es/ 该酷站收集了很多响应式设计的案例.全部都是收集的一些励志精美而时尚的网站,使用媒体查询和响应的网页设计. ...
- Jetty学习二:配置概览-怎么配置Jetty
Jetty POJO配置 Jetty的核心组件是Plain Old Java Objects(POJOs):配置Jetty的大部分工作就是在Jetty POJOs上的初始化.装配和设置域的处理,你能通 ...
- bzoj 1975 [Sdoi2010]魔法猪学院
1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1758 Solved: 557[Submit][Statu ...
- android:Activity四种启动模式简单介绍
Activity启动模式 能够依据实际的需求为Activity设置相应的启动模式,从而能够避免创建大量反复的Activity等问题 Activity有四种载入模式 1.standard(默认启动模式, ...
- 寻路DEMO
网格场景的寻路算法DEMO 灰色格子为默认正常蓝色格子表示为障碍物,不可进入红色细条在格子周围,表示格子的墙,用于阻碍行走紫色为当前鼠标选中格子黄色为寻路的起始位置和结束位置.鼠标左键设置,CTRL+ ...
- Linux进程调度的运行队列
当Linux内核要寻找一个新的进程在CPU上运行时,必须只考虑处于可运行状态的进程,(即在TASK_RUNNING状态的进程),因为扫描整个进程链表是相当低效的,所以引入了可运行状态进程的双向循环链表 ...
- scala 学习笔记五 foreach, map, reduce
例子 val v = Vector(,,,) ) println(s) //输出:Vector(2, 4, 6, 8) val v2 = Vector(,,,) var v3 = v2.reduce( ...