• 事件


    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执行了
    ");
    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执行了
    ");
    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放入缓冲区
    ", 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放入缓冲区
    ", 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放入缓冲区
    ", 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放入缓冲区
    ", 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 }
  • 相关阅读:
    完整版:资深程序员都了解的代码复用法则
    Shiro学习总结(10)——Spring集成Shiro
    Shiro学习总结(2)——Apache Shiro快速入门教程
    Shiro学习总结(2)——Apache Shiro快速入门教程
    Mysql学习总结(15)——Mysql错误码大全
    Mysql学习总结(15)——Mysql错误码大全
    ActiveMQ学习总结(6)——ActiveMQ集成Spring和Log4j实现异步日志
    ActiveMQ学习总结(6)——ActiveMQ集成Spring和Log4j实现异步日志
    对话:一个工程师在蘑菇街4年的架构感悟
    这种反爬虫手段有点意思,看我破了它!
  • 原文地址:https://www.cnblogs.com/hanhandaren/p/11141094.html
Copyright © 2020-2023  润新知