【问题标题】:Not getting WAIT_ABANDONED or WAIT_FAILED after exiting during wait等待期间退出后未获得 WAIT_ABANDONED 或 WAIT_FAILED
【发布时间】:2020-10-15 16:40:37
【问题描述】:

我正在设置一些进程间通信/内存共享,在此过程中,我正在尝试同步内存的初始设置。我希望我的子进程等待父进程完成 - 或者如果它失败,接管:

#include <windows.h>
#include <stdio.h>
//#include <coni
// o.h>
#include <tchar.h>
#include <iostream>
#include "mutex.cpp"

#define LOG(msg) std::cout << msg << std::endl

int _tmain() {
    HANDLE hSemaphore; // TODO: REFACTOR UNINITIALISED MEMORY

    std::string semaphoreName = std::string("test-semaphore");
    SetLastError(NULL);
    hSemaphore = CreateSemaphore(
            (LPSECURITY_ATTRIBUTES) NULL, // default security attributes
            0,
            LONG_MAX,
            semaphoreName.c_str() // named semaphore
    );

    if (hSemaphore == NULL) throw std::runtime_error("Failed to obtain mutex: " + semaphoreName);

    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        LOG("CHILD WAITING FOR SEMAPHORE");
        DWORD result = WaitForSingleObject(hSemaphore, 10000);
        if (result != WAIT_OBJECT_0) {
            switch (result) {
                case WAIT_TIMEOUT:
                    LOG("WAIT TIMED OUT");
                    break;
                case WAIT_FAILED:
                    // mutex closed
                    LOG("WAIT FAILED: " + std::to_string(GetLastError()));
                    break;
                case WAIT_ABANDONED:
                    // program holding mutex crashed / closed without closing mutex
                    LOG("WAIT ABANDONED");
                    break;
            }
            return 1;
        }

        LOG("CHILD AQUIRED SEMPAHORE");
        ReleaseSemaphore(hSemaphore, 1, NULL);
        LOG("CHILD RELEASED SEMPAHORE");
        return 0;
    } else {
        LOG("SIMULATING LONG OPERATION - SLEEPING 5 SECONDS");
        Sleep(5000);
        LOG("OPERATION DONE");

//        LOG("RELEASING SEMPAHORE");
//        ReleaseSemaphore(hSemaphore, 1, NULL);
//        LOG("RELEASED SEMPAHORE");
//
////      hold console-app
//        _getch();
        LOG("CLOSING SEMAPHORE HANDLE");
        CloseHandle(hSemaphore);
        LOG("SEMAPHORE HANDLE CLOSED");
        return 0;
    }
}

如您所见,我已注释掉父级释放信号量并休眠的行 - 相反,我关闭句柄并退出。

我所期望的是等待进程(在父进程之后大约一秒钟开始)得到一个放弃或失败的错误。相反,它只是超时。因此,如果我将超时设置为INFINITE,则该程序将在父级关闭时无限期停止。有谁知道这是否是预期的行为?

当我说父进程和等待进程时,我并不是说等待进程是父进程的子进程;父进程先来(并创建信号量),等待进程等待父进程释放。

【问题讨论】:

  • 根据docuWAIT_ABANDONED只为互斥量返回。
  • WAIT FAILED 只有在将无效句柄传递给 WaitForSingleObject 的情况下才会得到(无效句柄,不是可等待的对象句柄,句柄没有 SYNCHRONIZE 访问)。另一边关闭自我手柄 - 对您的 WaitForSingleObject 没有任何影响。 WAIT_ABANDONED 只为互斥体返回。
  • @RbMm 我现在正在使用互斥锁,ReleaseMutex 不会唤醒 WaitForSingleObject(mutexHandle, ...)。谢天谢地,Abandon 现在正在工作
  • @RbMm 释放互斥锁后,无法获取,每次都超时
  • 互斥锁只能在这个进程中接收

标签: c++ c multithreading winapi semaphore


【解决方案1】:

信号量仅在其计数器大于 0 时处于“已发出信号”状态。成功等待信号量会减少其计数器,因此必须在之后调用 ReleaseSemaphore() 以增加计数器。 “父级”正在创建初始计数器为 0 的信号量,而不是调用 ReleaseSemaphore() 来递增计数器,这就是为什么“子级”中的 WaitForSingleObject() 永远不会成功的原因。

当信号量的句柄关闭时,信号量的计数器不会改变This is documented behavior:

使用完信号量对象后,调用CloseHandle 函数关闭句柄。信号量对象在其最后一个句柄关闭时被销毁。 关闭句柄不影响信号量计数;因此,请务必在关闭句柄或进程终止之前调用ReleaseSemaphore()。否则,挂起的等待操作将超时或无限期继续,具体取决于是否指定了超时值。

这正是您所看到的。您有 2 个进程共享一个信号量对象。当“父级”关闭其信号量句柄时(隐含在进程退出时),该信号量仍然存在,直到子级也关闭其信号量句柄。但是由于信号量的计数器在“父”退出时不会改变,所以计数器永远不会是&gt; 0,因此信号量永远不会“发出信号”来满足“子”的等待。

当您改用互斥锁时,如果在成功等待后关闭互斥锁句柄而未调用ReleaseMutex(),则互斥锁将“被放弃”,直到随后的等待重新获得所有权。 This is also documented behavior:

如果线程在没有释放其对互斥对象的所有权的情况下终止,则认为该互斥对象被放弃。等待线程可以获得被放弃的互斥对象的所有权,但等待函数将返回WAIT_ABANDONED 表示放弃互斥对象。被放弃的互斥对象表示发生了错误,并且受互斥对象保护的任何共享资源都处于未定义状态。如果线程继续执行,就好像互斥对象没有被放弃一样,在线程释放其所有权后,它不再被视为已放弃。如果随后在等待函数中指定了互斥对象的句柄,这将恢复正常行为。

【讨论】:

  • 阅读后,我发现只有互斥锁放弃了覆盖——因为信号量不跟踪引用——没有办法弄清楚有人在没有释放的情况下崩溃了。因此,与互斥锁不同,使用信号量不会导致崩溃。这就是我试图涵盖的情况
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-06
  • 2021-09-24
  • 2012-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多