WaitForSingleObject 和事件,行为不明确

Posted

技术标签:

【中文标题】WaitForSingleObject 和事件,行为不明确【英文标题】:WaitForSingleObject and Events, unclear behaviour 【发布时间】:2018-12-12 08:07:34 【问题描述】:

我在 Windows 10 64 位上使用 Visual Studio 2017 编写了两个小测试应用程序,我想用它们测试事件和 WaitForSingleObject。

我也在使用来自 intervalzero 的 RTX 实时扩展。

我的一个应用程序是用 x64 代码编写的 windows 部分,另一个是 x64 代码用于 RTX 子系统。

现在我的想法是在 RTX 64 内创建一个事件,并在信号之间给定的暂停时间发出 10 次信号:

int _tmain(int argc, _TCHAR * argv[])


    RtPrintf("Starte RTX-Applikation\n");
    RtSleep(0);
    HANDLE hEvent = RtCreateEvent(NULL, false, false, _T("flexLZSStart"));
    if (hEvent != INVALID_HANDLE_VALUE)
    
        RtPrintf("Event erzeugt\n");
        for (size_t i = 0; i < 10 ; i++)
        
                RtSetEvent(hEvent);
                RtPrintf("Event gesetzt\n");
                RtSleep(1500);
        
        RtCloseHandle(hEvent);
    

    RtPrintf("exit process\n");
    return 0;

另一方面,windows 应用程序检查事件的创建,然后重复检查事件是否发出信号:

int main()

    Sleep(150);
    HANDLE hEvent = NULL;
    DWORD dwstart = GetTickCount();
    printf("wait for creation of event\n");
    while (hEvent == NULL)
    
        hEvent = RtOpenEvent(NULL, NULL, _T("flexLZSStart"));
    
    if ((hEvent == INVALID_HANDLE_VALUE) || (hEvent == NULL))
    
        exit(-2);
    
//#define REOPEN
    if ((hEvent != INVALID_HANDLE_VALUE) && (hEvent != NULL))
    
        DWORD dwErg;
        BOOLEAN aborted = false;
        printf("Event has been created.\n");
#ifdef REOPEN
        RtCloseHandle(hEvent);
#endif
        do
        
            printf("Wait for event to be signaled\n");
#ifdef REOPEN
            hEvent = RtOpenEvent(NULL, NULL, _T("flexLZSStart"));
            if (hEvent == NULL)
            
                printf("Event has been disposed?\n");
                break;
            
#endif
            dwErg = RtWaitForSingleObject(hEvent,1000);
#ifdef REOPEN
            RtCloseHandle(hEvent);
#endif
            DWORD dwLastError = GetLastError();
            if (dwLastError != 0)
            
                printf("GetLastError returned %d!\n", dwLastError);
            
            switch (dwErg)
            
            case WAIT_OBJECT_0:
                printf("received Event\n");
                RtResetEvent(hEvent);
                break;
            case WAIT_TIMEOUT:
                //printf("event not yet received\n");
                break;
            case WAIT_ABANDONED:
            
                printf("owner of event has been killed\n");
                aborted = true;
            
            break;
            default:
            
                printf("no valid return value: %d\n", dwErg);
                aborted = true;
            
            break;
            
         while (!aborted);

    
    printf("loop exited\n");
    exit(0);

现在我的观察是,RTX 代码运行良好,并在发出 10 次事件信号后退出。

另一方面,windows 代码接收事件 10 次,但它没有检测到 rtx 应用程序何时关闭事件。

如果我在定义 REOPEN 的情况下编译代码,Windows 代码会以 11. open 事件退出,因为它不再可用。

我应该通过第二个事件来增强我的代码,该事件由 windows 代码在收到第一个事件后触发,以便 rtx 代码等到 windows 代码完成其工作。

但我的最后一个问题是:

检测事件源是否仍然有效的正确方法是什么?

我能否检测到 rtx 代码在最终退出之前已创建事件,但尚未发出信号?

【问题讨论】:

正确的解决办法是不要在你的程序还在使用它的时候关闭它。这是常识,真的。如果您需要关闭多个线程,您也可以为此设置一个事件,然后让它们在关闭句柄之前自行优雅地完成。 @Lundin,这不是我问题的重点。如果创建事件的程序在没有为另一个程序设置事件的情况下崩溃,我就没有机会查看该事件是否仍然有效。也许很久以前两个程序都创建/打开了事件,waitforsingleobject 可能引用了一个无效的句柄,因为创建程序已经退出...... @WolfgangRoth "如果创建事件的程序在没有设置事件以通知另一个程序的情况下崩溃,我就没有机会查看该事件是否仍然有效" - 内核对象,如事件,是引用计数的。只要对象有打开的句柄,它就仍然有效。在对象的所有句柄都关闭之前,它不会被销毁。当进程因任何原因终止时,操作系统将自动关闭它仍然打开的所有句柄... @WolfgangRoth ... 所以,假设进程 A 创建一个事件 (refcnt=1),然后进程 B 打开事件以等待它 (refcnt=2)。如果进程 A 然后崩溃并退出(refcnt=1),但进程 B 仍然有一个打开的事件句柄(refcnt=1),则事件仍然有效。然后,您可以重新启动进程 A,它可以为现有事件 (refcnt=2) 打开一个新句柄并继续,就像什么都没发生一样。 【参考方案1】:

由于我对这两个应用程序的编程方式,无法检测到 sender 已结束。

为了检测到这一点,我应该实现另一个在 sender 退出时触发的互斥锁。所以 receiver 可以检测到发出信号的互斥体并自行退出。

【讨论】:

以上是关于WaitForSingleObject 和事件,行为不明确的主要内容,如果未能解决你的问题,请参考以下文章

WaitForSingleObject用法介绍

单个 SetEvent() 能否触发多个 WaitForSingleObject()

WaitForSingleObject 死锁

CreateEvent和SetEvent及WaitForSingleObject的使用方法

用户模式同步之事件小解

Delphi WinAPI WaitForSingleObject-等待函数-等待指定对象处于有信号状态或超时间隔结束。