与 POSIX 等待机制最接近的 Windows 是什么?

nor*_*itt 3 c windows monitoring status wait

Linux 支持“sys/wait.h”中定义的 POSIX 等待机制。方法wait、waitid、waitpid可用于在使用fork创建的父进程和子进程之间交换状态信息。

Windows 既不提供 fork 的(本机)支持,也不提供 POSIX 等待机制。相反,还有其他方法可用于 spwan 子进程,即CreateProcess

将使用 fork/wait 用 C 或 C++ 编写的 linux 应用程序移植到 Windows 时,监视父进程中子进程的状态更改(即WEXITED、WSTOPPED、WCONTINUED)的最合适的本机*方法是什么?

*本机意味着不使用不随 Windows 附带或由 MS 以运行时环境形式直接提供的其他库、框架、程序(如 cygwin、minGW)。

编辑:根据评论中的要求,我确实以伪代码的形式提供了一些关于应该解决什么问题的更多信息:

//creates a new child process that is a copy of the parent (compare 
//POSIX fork()) and returns some sort of handle to it.
function spawnChild() 

// returns TRUE if called from the master process FALSE otherwise
function master()

// return TRUE if called from a child process FALSE otherwise
function child()

// returns TRUE if child process has finished its work entirely, 
// FALSE otherwise.
function completelyFinished()

//sends signal/message "sig" to receive where receiver is a single 
//handle or a set of handles to processes that shall receive sig
function sendSignal(sig, receiver)

// terminates the calling process
function exit()

// returns a handle to the sender of signal "sig"
function senderOf(sig)

function masterprocess()
  master //contains handle to the master process
  children = {}   //this is an empty set of handles to child processes
  buf[SIZE]  //some memory area of SIZE bytes available to master process and all children
  FOR i = 0 TO n - 1
    //spawn new child process and at its handle to the list of running 
    //child processes.
    children <- children UNION spawnChild() 
  IF(master())
    <logic here>
    sendSignal(STARTWORKING, children) //send notification to children
    WHILE(signal = wait())  // wait for any child to respond (wait is blocking) 
      IF signal == IMDONE
        <logic here (involving reads/writes to buf)>
        sendSignal(STARTWORKING, senderOf(signal))
      ELSEIF signal == EXITED
        children <- children \ signal.sender //remove sender from list of children
  ELSEIF(child())
    WHILE(wait() != STARTWORKING);
       <logic here (involving reads/writes to buf)>
       IF completelyFinished()
         sendSignal(EXITED, master)
         exit()
       ELSE
         sendSignal(IMDONE, master)
Run Code Online (Sandbox Code Playgroud)

Har*_*ton 5

在我回答实际问题之前,我将推荐一个更好的解决方案:您应该考虑简化父子之间的关系。

基于伪代码,父母和孩子之间的信号是作为跨进程互斥锁的一种粗略形式,即,他们所做的只是阻止这里的代码:

  IF signal == IMDONE
    <logic here (involving reads/writes to buf)>
    sendSignal(STARTWORKING, senderOf(signal))
Run Code Online (Sandbox Code Playgroud)

同时运行多个实例。相反,<logic here>应该移动到相应的子进程中,由互斥锁保护,以便一次只有一个子进程可以运行它。

那时,父级需要做的就是启动子级并等待它们全部退出。通过等待进程句柄,这在 Windows 中很容易完成。

(我想现代 POSIX 还支持某种比信号更复杂的跨进程互斥锁。)


还值得重新考虑您是否真的需要多个进程。多线程会更有效率,如果代码写得好,适应起来应该不难。


尽管如此,如果由于某种原因你绝对必须尽可能多地保留原始程序结构,管道可能是你最好的选择。

  • 发送信号变成写入单个字节。

  • 在子进程中,等待来自父进程的信号变成了读取单个字节。

  • 在父进程中等待来自任何一个子进程的消息有点棘手。它仍然是单字节读取(对于每个孩子),但您需要使用重叠 I/O,如果您需要支持超过 64 个孩子,则IOCP

(或者,您可以使用多个线程,但这可能涉及太多的结构更改。)

  • 如果管道正确实现,当子进程退出或死亡时,父进程中相应的读取操作将因ERROR_BROKEN_PIPE错误而终止。因此,不需要单独的机制来监控儿童的健康状况。

在这种情况下,我认为匿名管道将是最合适的选择。这些是单工的,所以每个孩子都需要两个管道。您可以将子进程的管道句柄末端作为子进程的标准输入和输出传递。

对于匿名管道,您需要确保在启动每个子管道后关闭父级的句柄副本,并且每个子管道仅继承与其自己管道对应的句柄。如果有任何额外的句柄在子管道的末端打开,当子进程退出时父进程将不会收到任何通知。


这些都不是特别复杂,但请注意命名管道 I/O 有一点学习曲线。异步 I/O 更是如此,特别是如果您来自 UNIX 背景。请特别注意,要使用异步 I/O,您需要发出一个操作,然后等待它完成,这与 UNIX 模型相反,在 UNIX 模型中,您等待 I/O 准备好然后发出操作。