Linux支持在" sys / wait.h"中定义的POSIX等待机制。方法wait, waitid, waitpid可用于在使用fork创建的父进程和子进程之间交换状态信息。
Windows既没有为fork提供(本机)支持,也没有提供POSIX等待机制。相反,还有其他方法可用于spwan子进程,即CreateProcess。
使用fork / wait向Windows移植使用C或C ++编写的Linux应用程序时,最适合的 native * 方式监视子进程的状态更改(即WEXITED, WSTOPPED, WCONTINUED)父进程?
* native 意味着不使用其他库,框架,程序(如cygwin,minGW),这些库不包含在Windows中,或者由MS以运行时环境的形式直接提供。
编辑:根据评论中的要求,我确实提供了一些关于应该以伪代码形式解决的问题的更多信息:
//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)
答案 0 :(得分:4)
在回答实际问题之前,我将建议一个更好的解决方案:您应该考虑简化父母和孩子之间的关系。
基于伪代码,父母和孩子之间的信号作为cross-process mutex的粗略形式,即他们所做的就是阻止代码:
IF signal == IMDONE
<logic here (involving reads/writes to buf)>
sendSignal(STARTWORKING, senderOf(signal))
同时运行多个实例。相反,应将<logic here>
移动到相应的子进程中,由互斥锁保护,以便一次只能运行一个子进程。
此时,所有父母需要做的就是启动孩子并等待他们全部退出。通过等待进程句柄,可以在Windows中轻松完成。
(我认为现代POSIX还支持某种比信号更复杂的跨进程互斥体。)
重新考虑是否真的需要多个流程也是值得的。多线程会更有效,如果代码写得正确,那么应该很难适应它。
尽管如此,如果由于某种原因你绝对必须保留尽可能多的原始程序结构,pipes可能会是你最好的选择。
发送信号会写入一个字节。
在孩子中,等待来自父母的信号会变成单个字节。
在父母那里等待来自任何一个孩子的消息有点麻烦。它仍然是一个单字节读取(对于每个孩子),但您需要使用overlapped I/O,如果您需要支持超过64个孩子,IOCP。
(或者,您可以使用多个线程,但这可能涉及太多的结构更改。)
ERROR_BROKEN_PIPE
错误终止。因此,不需要单独的机制来监测孩子的健康状况。在这种情况下,我认为anonymous pipes是最合适的选择。这些都是单面的,因此每个孩子都需要两个管道。您可以将子句柄的子句末端作为子进程的标准输入和输出传递。
对于匿名管道,您需要确保在每个子项启动后关闭父句柄的父副本,并且每个子项仅继承与其自己的管道对应的句柄。如果孩子的管道末端有任何额外的手柄处于打开状态,则当孩子退出时,父母将不会收到任何通知。
这一切都不是特别复杂,但要注意命名管道I / O有一点学习曲线。异步I / O更是如此,特别是如果您来自UNIX背景。请特别注意,要使用异步I / O,请发出操作然后等待它完成,而不是等待I / O准备就绪的UNIX模型,然后发出操作。
答案 1 :(得分:2)
如果要向其他进程发出布尔条件信号,可能应该使用共享事件。您可以通过名称或句柄复制来共享它们。你可以随意拥有这些信号。例如,您可以为每个WEXITED, WSTOPPED, WCONTINUED
分配一个。
看到你的编辑:事件很棒。在父项中创建命名事件,并将命令上的名称传递给子项。这样父母和孩子就可以互相发出信号。
您还需要共享内存部分,例如通过内存映射文件。这与您代码中的buf
相对应。
答案 2 :(得分:2)
你在那里看到的是一个工作队列安排,你有一个生产者进程和一堆工作进程。目前还不清楚您是将共享内存仅用作工作队列,还是您的工作人员正在 on 共享内存(可能是一个巨大的矩阵或向量问题)。
在Win32中,您可能不会将其作为单独的进程实现。
您将使用已经共享内存(相同地址空间)的生产者/消费者线程集合,并使用信号量或条件变量实现工作队列。
实际上,您可能使用更高级别的抽象,例如QueueUserWorkItem。这使用默认的Windows线程池,但您可以使用CreateThreadpool创建自己的线程池。