首页 > 其他 > 详细

CreateEvent函数使用记录

时间:2020-06-18 13:55:17      阅读:58      评论:0      收藏:0      [点我收藏+]

最近在写一个串口对话框程序,使用到了CreateEvent函数。于是就特地谷歌了一番。

总体感觉就是CreateEvent相当于创建了一个信号灯,在A线程里面点灯(SetEvent),在B线程中观察等待(WaitForSingleObject),看到灯亮了就开始干活。

创建信号灯的时候:

  1. 可以设定信号灯是否人工(手动)关闭(CreateEvent的第二个参数),TRUE为手动关闭,FALSE为自动关闭。
  2. 可以设定信号灯的初始状态(CreateEvent的第三个参数)为TRUE或者FALSE。

所谓的人工关闭,就是程序员在合适的地方主动调用ResetEvent来关闭信号灯。

而信号灯的状态决定了WaitForSingleObject是否可以结束等待,如果为TRUE则结束等待,否则根据WaitForSingleObject的最后一个参数来决定等待多久。

 

 

对于一个线程,不可能即观察一个灯的状态,同时又自己来对这个灯进行点灯、灭灯操作,这样做没有任何意义。

 

总结信号灯的使用需要涉及如下五点:

  1. 创建信号灯。调用CreateEvent,要与CloseHandle成对使用。
  2. 创建观察信号灯的线程。
  3. 设置信号灯的状态。就是点灯了,把灯点亮,告诉需要观察这个灯状态的线程注意干活。
  4. 复位信号灯的状态。取决于创建信号灯的时候是否人工复位。
  5. 删除信号灯。调用CloseHandle来删除,等于是释放内存。

为此,写了如下一段测试代码。主要就是两个线程和两个信号灯:

  1. 填充线程。功能是观察fillable信号灯,当fillable灯亮之后,就灭fillable灯,然后往全局buffer里面填充数据,再点亮fetchable灯。
  2. 拉取线程。功能是观察fetchable信号灯,当fetchable灯亮之后,就灭fetchable灯,接着从全局buffer里面读取数据,最后再点亮fillable灯。

 

对于信号灯的初始化(CreateEvent函数的第三个参数),自然是fillable要初始化为亮灯状态,fetchable要初始化为灭灯状态。很自然地,没有数据你怎么去fetch嘛,所以必然要先fill,后fetch,这就是这两个信号灯的初值了。

 

对于主线程中的 WaitForMultipleObjects 函数,顾名思义,自然就是等待多个信号条件都满足的时候才会结束等待,这与我们在新开线程中使用的WaitForSingleObject算是一对兄弟了。所以主线程中创建两个子线程以后,不能自己直接结束了,应该要调用WaitForMultipleObjects来等待两个子线程的结束,然后删除信号灯,要不然可能内存泄露。

// createevent.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>



static HANDLE mEventHandle_fillable;
static HANDLE mEventHandle_fetchable;
static char mSharedBuffer[128] = {0};
static const char *stop_keyword = "\r\nSTOP\r\n";

static DWORD WINAPI fill_thread(LPVOID lpParam)
{
    int i = 0;

    while(WAIT_OBJECT_0 == WaitForSingleObject( 
        mEventHandle_fillable,
        INFINITE))
    {
        if (i < 3)
        {
            sprintf_s(mSharedBuffer, sizeof(mSharedBuffer), "%d", i);
            ResetEvent(mEventHandle_fillable);
            printf("Please fetch your data.\n");
            SetEvent(mEventHandle_fetchable);
        }
        else
        {
            strcpy_s(mSharedBuffer, sizeof(mSharedBuffer), stop_keyword);
            ResetEvent(mEventHandle_fillable);
            printf("Fill finish. We can have a rest.\n");
            SetEvent(mEventHandle_fetchable);
            break;
        }
        
        i++;
    }

    printf("fill_thread exit with code 0, last error=%d\n", GetLastError()); 
    return 0;
}

static DWORD WINAPI fetch_thread(LPVOID lpParam)
{
    while(WAIT_OBJECT_0 == WaitForSingleObject( 
        mEventHandle_fetchable,
        INFINITE))
    {
        if (0 == strcmp(mSharedBuffer, stop_keyword))
        {
            ResetEvent(mEventHandle_fetchable);
            printf("\nGot. We must have a rest!\n");
        }
        else
        {
            printf("fetched \"%s\".\n", mSharedBuffer);
            mSharedBuffer[0] = 0;
            ResetEvent(mEventHandle_fetchable);
            Sleep(3000);
            printf("Please fill.\n\n");
            SetEvent(mEventHandle_fillable);
        }
    }
     
    printf("fetch_thread exit with code 0, last error=%d\n", GetLastError()); 
    return 0;
}

static void test_entry(void)
{
    static HANDLE threads[2];
    DWORD tid;

    mEventHandle_fillable = CreateEvent(NULL, TRUE, TRUE, TEXT("fillable"));
    mEventHandle_fetchable = CreateEvent(NULL, TRUE, FALSE, TEXT("fetchable"));

    threads[0] = CreateThread(NULL, 0, fill_thread, NULL, 0, &tid);
    threads[1] = CreateThread(NULL, 0, fetch_thread, NULL, 0, &tid);

    WaitForMultipleObjects(2, threads, TRUE, INFINITE);

    CloseHandle(mEventHandle_fillable);
    CloseHandle(mEventHandle_fetchable);
}

int _tmain(int argc, _TCHAR* argv[])
{
    test_entry();
    printf("\n\n***\npress ENTER key to exit!\n");
    getchar();
    return 0;
}

测试截图截图

技术分享图片

代码逻辑图

技术分享图片

 

参考:https://docs.microsoft.com/en-us/windows/win32/sync/using-event-objects

CreateEvent函数使用记录

原文:https://www.cnblogs.com/ssdq/p/13157077.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!