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