这是整理孙鑫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++线程同步-事件对象的更多相关文章

  1. VC++ 线程同步 总结

    注:所谓同步,并不是多个线程一起同时执行,而是他们协同步调,按预定的先后次序执行. 与线程相关的基本函数包括:CreateThread:创建线程CloseHandle:关闭线程句柄.注意,这只会使指定 ...

  2. 经典线程同步 事件Event

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题 ...

  3. 多线程面试题系列(6):经典线程同步 事件Event

    上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的"线程所有权"特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题.首先 ...

  4. 转--- 秒杀多线程第六篇 经典线程同步 事件Event

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题 ...

  5. 秒杀多线程第六篇 经典线程同步 事件Event

    原文地址:http://blog.csdn.net/morewindows/article/details/7445233 上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权” ...

  6. C#线程学习笔记五:线程同步--事件构造

    本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html,记录一下学习过程以备后续查用. 前面讲的线 ...

  7. MFC线程(三):线程同步事件(event)与互斥(mutex)

    前面讲了临界区可以用来达到线程同步.而事件(event)与互斥(mutex)也同样可以做到. Win32 API中的线程事件 HANDLE hEvent = NULL; void MainTestFu ...

  8. java线程同步以及对象锁和类锁解析(多线程synchronized关键字)

    一.关于线程安全 1.是什么决定的线程安全问题? 线程安全问题基本是由全局变量及静态变量引起的. 若每个线程中对全局变量.静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的:若有多个线 ...

  9. VC++线程同步之临界区(CriticalSection)

    1.相关文件和接口 #include <windows.h> CRITICAL_SECTION cs;//定义临界区对象 InitializeCriticalSection(&cs ...

随机推荐

  1. android studio 引用aar

    在:libs拷贝对应的文件 build.gradle repositories {    flatDir {        dirs 'libs'    }}dependencies {   // c ...

  2. Selenium2+python自动化29-js处理多窗口

    前言 在打开页面上链接的时候,经常会弹出另外一个窗口(多窗口情况前面这篇有讲解:Selenium2+python自动化13-多窗口.句柄(handle)),这样在多个窗口之间来回切换比较复杂,那么有没 ...

  3. Windows和Linux下如何查看端口被哪个进程占用

    Windows: C:/Users/ewanbao>netstat -aon|findstr "123"  TCP    127.0.0.1:55123        0.0 ...

  4. Ladda 应用提交表单的时候显示loading载入中 包含不同位置,不同效果

    Ladda 应用提交表单的时候显示loading载入中 包含不同位置,不同效果 不同大小.位置,效果,进度条等 演示 XML/HTML Code <article class="exa ...

  5. poj 3041 Asteroids 题解

    Asteroids Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20686   Accepted: 11239 Descr ...

  6. 洛谷P1772 [ZJOI2006]物流运输 题解

    题目描述 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪. ...

  7. Spark从HDFS上读取JSON数据

    代码如下: import org.apache.spark.sql.Row; import org.apache.spark.SparkConf; import org.apache.spark.ap ...

  8. Spring MVC 4.2 CORS 跨域访问

    跨站 HTTP 请求(Cross-site HTTP request)是指发起请求的资源所在域不同于该请求所指向资源所在的域的 HTTP 请求.比如说,域名A(http://domaina.examp ...

  9. IE6的3像素神奇bug:缘起与解决方案

    在我们这样一个神奇的国度,到了2014年了,居然还是有很多人的电脑上用着XP,安装的是IE6,他们没有想过要升级,我们就得想着兼容他们.... 一. 6爷我喝高了,最后一行有重影.那什么是IE6 的3 ...

  10. android 时间控件概述

    android的自带时间选择控件,是一个让用户既能输入的又能选择的样子.这本来没有太大的问题了. 但是,坑爹的android是开源的.自带的时间控件在某些机型上,早已经是面目全非了,在用以一个普通用户 ...