• Win32 线程同步-利用Event实现生产者消费者问题


    一.什么是线程同步

    首先,我们要明确线程同步的概念,所谓线程同步

    就是让线程执行顺序是有序的.因为互斥可以保证A访问的时候B访问不了.但有可能A会访问多次.线程无序.此时同步的意思就是 我就想让A执行完在执行B.

    这个就是同步.

    二.Win32API  事件

    事件,是Win32中管理线程同步所使用的API。

    HANDLE CreateEventA(
      LPSECURITY_ATTRIBUTES lpEventAttributes,  // SD安全属性
      BOOL                  bManualReset,                  //通知类型
      BOOL                  bInitialState, //初始值有信号还是无信号.false无信号
      LPCSTR                lpName                          //全局名字
    );        
          返回事件句柄                                                             

    第三个参数我们很好理解. 有信号还是无信号.  false为无信号. true为有信号.  这样Wait函数根据有无信号就可以进行线程是否执行了.

    主要是第二个参数. 通知类型.这个比较复杂.

    通知类型的意思就是指.  如果我们按照以前.我们使用了wait函数. 那么有信号会变为无信号.除非释放才会继续有信号执行.

    而现在的通知类型如果为TRUE. 那么wait函数执行的时候.你有信号我不会自动变为无信号了.除非你手动自己更改.

    如果通知类型为FALSE 那么则自动设置.有信号使用wait函数接受了.那么就变成无信号了.

    BOOL SetEvent(HANDLE hEvent);
                                            //设置信号状态,转为已通知状态

    三.利用Event实现生产者消费者问题

    下面给出源码,解释已经非常详细,不再进行过多讲解

    #include "stdafx.h"
    #include <Windows.h>
    #include "Mycpp.h"   //这是本人添加的库文件,可忽略
    HANDLE g_hSet;     //将句柄声明为全局变量,方便使用
    HANDLE g_hClear;
    int g_Max=10;     //给定变量初始值
    int g_Num=0;
    
    
    DWORD WINAPI ThreadProc1(LPVOID lpParameter)    //生产者线程函数                        
    {                            
        for(int i =0;i<g_Max;i++)
        {
            WaitForSingleObject(g_hSet,INFINITE);             //因为g_Set的初始状态为已通知,所以可以立即执行下面的代码,且状态会被改变为未通知
            g_Num=1;
            DWORD id = GetCurrentThreadId();                  //该API获取线程的ID
            printf("生产者%d将数据%d放入缓冲区
    ",id,g_Num);
            SetEvent(g_hClear);                                //这里会将g_hClear的状态设置为已通知状态,即消费者线程函数的Wait接收到信号并执行
        }
    
        return 0;
    }                            
                                
    DWORD WINAPI ThreadProc2(LPVOID lpParameter)   //消费者线程函数                            
    {                            
        for(int i =0;i<g_Max;i++)
        {
            WaitForSingleObject(g_hClear,INFINITE);        //执行以下代码,并将g_hClear的状态设置为未通知
            g_Num=0;
            DWORD id = GetCurrentThreadId();
            printf("消费者%d将数据%d放入缓冲区
    ",id,g_Num);
            SetEvent(g_hSet);                        //再将g_hSet的状态设置为已通知,实现同步执行,即生产者生产,消费者立马消费
        }    
        return 0;
    }                            
                                
    int main(int argc, char* argv[])                            
    {                            
        HANDLE hThread[2];                                               //创建一个句柄数组
        g_hSet = CreateEvent(NULL,FALSE,TRUE,NULL);                        //分别创建两个事件,其中g_hSet(生产者事件)初始状态设置为已通知状态,即Wait后可以立即执行
        g_hClear = CreateEvent(NULL,FALSE,FALSE,NULL);
        hThread[0]= CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
        hThread[1]= CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);
        WaitForMultipleObjects(2,hThread,TRUE,INFINITE);            //当上述线程执行完毕后,执行以下代码
        CloseHandle(hThread[0]);                                //  关闭句柄,销毁内核对象
        CloseHandle(hThread[1]);
        CloseHandle(g_hSet);
        CloseHandle(g_hClear);
        return 0;                        
    }                            

    执行后结果为:

    至此,我们已经利用Event实现了线程同步问题

  • 相关阅读:
    Linux下的lds链接脚本简介
    Fedora下载地址
    SkyEye的使用
    shell变量详解
    Linux shell 脚本攻略之正则表达式入门
    Linux shell 脚本攻略之统计文件的行数、单词数和字符数
    Linux shell 脚本攻略之创建不可修改文件
    Linux shell 脚本攻略之生成任意大小的文件
    Linux shell 脚本攻略之批量重命名
    Linux shell 脚本攻略之文件查找与文件列表
  • 原文地址:https://www.cnblogs.com/Virus-Faker/p/12402439.html
Copyright © 2020-2023  润新知