事件

1.通知类型

 

HANDLECreateEvent(
LPSECURITY_ATTRIBUTESlpEventAttributes,// 安全属性
BOOLbManualReset,// 复位方式
BOOLbInitialState,// 初始状态
LPCTSTRlpName // 对象名称
);

    该函数创建一个Event同步对象,如果CreateEvent调用成功的话,会返回新生成的对象的句柄,否则返回NULL。

 

参数说明:

    lpEventAttributes     一般为NULL   


    bManualReset               创建的Event是自动复位还是人工复位.如果true,人工复位,   一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复 为无信号.     如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,  该Event就会自动复位,变成无信号.   如果想 在每次调用WaitForSingleObject 后让WINDOWS为您自动地把事件地状态恢复为”无信号”状态,必须把该参数设为FALSE,否则,您必须每次调用ResetEvent函数来清除事件 的信号。


    bInitialState             初始状态,true,有信号,false无信号   
    lpName                  事件对象的名称。您在OpenEvent函数中可能使用。

 1 // 事件.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <windows.h>
 6 
 7 
 8 HANDLE g_hEvent;
 9 
10 DWORD WINAPI ThreadPro_1(LPVOID IpParameter)
11 {
12     TCHAR szBuffer[10] = { 0 };
13     
14     //当事件变成已通知时
15     WaitForSingleObject(g_hEvent,INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号
16     //线程执行
17     printf("ThreadPro_1执行了\n");
18     getchar();
19 
20     return 0;
21 }
22 DWORD WINAPI ThreadPro_2(LPVOID IpParameter)
23 {
24     TCHAR szBuffer[10] = { 0 };
25 
26     //当事件变成已通知时
27     WaitForSingleObject(g_hEvent, INFINITE);//一直等待信号
28                                             //线程执行
29     printf("ThreadPro_2执行了\n");
30     getchar();
31     SetEvent(g_hEvent);
32 
33     return 0;
34 }
35 int main()
36 {
37     //创建事件
38     //默认安全属性 TRUE 通知/FALSE互斥 初始没信号 没有名字
39     g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
40     HANDLE hThread[2];
41     //创建两个线程
42     hThread[0] = CreateThread(NULL, 0, ThreadPro_1, NULL, 0, NULL);
43     hThread[1] = CreateThread(NULL, 0, ThreadPro_2, NULL, 0, NULL);
44 
45     //设置事件为已通知
46     SetEvent(g_hEvent);
47     
48 
49     //等待线程结束,销毁内核对象
50     WaitForMultipleObjects(2, hThread, TRUE, INFINITE);//等待两个线程都运行完毕
51     CloseHandle(hThread[0]);
52     CloseHandle(hThread[1]);
53     CloseHandle(g_hEvent);
54 
55 
56     return 0;
57 }

2.线程同步

    同步的前提是互斥。

同步 = 互斥  +  有序 

  下面用生产者消费者问题来做个阐述:

// 生产者消费者问题.cpp : 定义控制台应用程序的入口点。
//
//只能互斥不能实现同步
#include "stdafx.h"
#include <windows.h>


HANDLE hMutex;
int  g_Max = 10;  //生产几个产品
int g_Number = 0;    //容器 存储产品
DWORD WINAPI ThreadProduct(LPVOID IpParameter)
{
    for (int i =0 ; i<g_Max;i++)
    {
        //互斥的访问缓冲区
        //当事件变成已通知时
        WaitForSingleObject(hMutex, INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号
        g_Number = 1;
        DWORD id = GetCurrentThreadId();//获取当前正在执行线程的ID
        printf("生产者%d将数据%d放入缓冲区\n", id, g_Number);
        ReleaseMutex(hMutex);
    }
    

    return 0;
}
DWORD WINAPI ThreadConsumer(LPVOID IpParameter)
{
    for (int i = 0; i < g_Max; i++)
    {
        //互斥的访问缓冲区
        //当事件变成已通知时
        WaitForSingleObject(hMutex, INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号
        g_Number = 0;
        DWORD id = GetCurrentThreadId();//获取当前正在执行线程的ID
        printf("消费者%d将数据%d放入缓冲区\n", id, g_Number);
        ReleaseMutex(hMutex);
    }


    return 0;
}
int main()
{
    //创建事件
    //默认安全属性 TRUE 通知/FALSE互斥 初始没信号 没有名字
    hMutex = CreateMutex(NULL, FALSE ,NULL);
    HANDLE hThread[2];
    //创建两个线程
    hThread[0] = CreateThread(NULL, 0, ThreadProduct, NULL, 0, NULL);
    hThread[1] = CreateThread(NULL, 0, ThreadConsumer, NULL, 0, NULL);


    getchar();
    //等待线程结束,销毁内核对象
    WaitForMultipleObjects(2, hThread, TRUE, INFINITE);//等待两个线程都运行完毕
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);
    CloseHandle(hMutex);


    return 0;
}

改良后利用事件实现同步:

 1 // 生产者消费者问题.cpp : 定义控制台应用程序的入口点。
 2 //
 3 //只能互斥不能实现同步
 4 #include "stdafx.h"
 5 #include <windows.h>
 6 
 7 
 8 HANDLE g_hSet,g_hClear;
 9 
10 int  g_Max = 10;  //生产几个产品
11 int g_Number = 0;    //容器 存储产品
12 DWORD WINAPI ThreadProduct(LPVOID IpParameter)
13 {
14     for (int i =0 ; i<g_Max;i++)
15     {
16         //互斥的访问缓冲区
17         //当事件变成已通知时
18         WaitForSingleObject(g_hSet, INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号
19         g_Number = 1;
20         DWORD id = GetCurrentThreadId();//获取当前正在执行线程的ID
21         printf("生产者%d将数据%d放入缓冲区\n", id, g_Number);
22         SetEvent(g_hClear);//生产者执行完后放开消费者的信号
23     }
24     
25 
26     return 0;
27 }
28 DWORD WINAPI ThreadConsumer(LPVOID IpParameter)
29 {
30     for (int i = 0; i < g_Max; i++)
31     {
32         //互斥的访问缓冲区
33         //当事件变成已通知时
34         WaitForSingleObject(g_hClear, INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号
35         //执行完后自动将信号设置为0;
36         g_Number = 0;
37         DWORD id = GetCurrentThreadId();//获取当前正在执行线程的ID
38         printf("消费者%d将数据%d放入缓冲区\n", id, g_Number);
39         SetEvent(g_hSet);//消费者执行完后放开生产者的信号
40     }
41 
42 
43     return 0;
44 }
45 int main()
46 {
47     //创建事件
48     //默认安全属性 TRUE 通知/FALSE互斥 初始没信号 没有名字
49     g_hSet = CreateEvent(NULL,FALSE, TRUE ,NULL); //生产者初始有信号
50     g_hClear = CreateEvent(NULL, FALSE, FALSE, NULL);
51     HANDLE hThread[2];
52     //创建两个线程
53     hThread[0] = ::CreateThread(NULL, 0, ThreadProduct, NULL, 0, NULL);
54     hThread[1] = ::CreateThread(NULL, 0, ThreadConsumer, NULL, 0, NULL);
55 
56 
57     getchar();
58     //等待线程结束,销毁内核对象
59     WaitForMultipleObjects(2, hThread, TRUE, INFINITE);//等待两个线程都运行完毕
60     CloseHandle(hThread[0]);
61     CloseHandle(hThread[1]);
62     CloseHandle(g_hSet);
63     CloseHandle(g_hClear);
64 
65     return 0;
66 }

 

posted @ 2019-07-05 22:34  瀚瀚大人  阅读(137)  评论(0编辑  收藏  举报