2017-01-19 53 views
2

场景:如何等待未知数量的进程结束

有一台机器上运行多个进程。名字和句柄未知,但它们都有一段代码在我们的控制下运行。

运行命令行进程。它向其他进程发信号表示它们需要结束(SetEvent),我们的代码会在其他进程中进行处理。

目标:

的命令行程序需要等待,直到其他进程已经结束。这怎么能实现?

想到的只是设置一些共享内存或其他东西,并让每个进程都将其句柄写入其中,以便命令行进程可以在其上等待,但这看起来像是付出了很多努力。必须有一些可以等待的内核级引用计数?

编辑1:

我想,也许分配流程,工作对象,然后在命令行程序可以等待呢?不理想,但...

编辑2:

不能使用作业对象,因为它会使用其他工作干扰的东西。所以现在我认为这些进程会获得一些/任何同步对象(信号量,事件等)的句柄,并且命令行进程将轮询它的存在。它将不得不轮询,如果它等待它将保持对象活着。同步对象在进程死亡时被窗口清除,所以下一次轮询会指示没有进程。不是最好的,最干净的方法,但它足够简单,足以完成它需要做的工作。有什么进展?

+0

使用命名管道为您的客户端进程传达其进程ID或重复的进程句柄,并让服务器进程等待所有这些进程句柄。无论进程如何终止(正常停顿,崩溃),进程句柄都会发出信号。 – IInspectable

+0

'也许将进程分配给作业对象vs处理未知。过程如何创建?一次全部 ?或者在一段时间内可以创建新的流程? – RbMm

+0

@RbMm处理命令行进程未知的事件。进程本身可以知道自己的句柄并将自己添加到作业对象中。用户可以自由运行并自由终止这些过程。 – parrowdice

回答

2

您可以采取以下任一种方式。

共享内存(内存映射对象):CreateFileMapping,然后MapViewOfFile - >执行请求。 UnmapViewFile。关闭文件,

命名管道:为每个应用程序创建一个命名管道。并继续运行一个线程来读取文件。因此,您可以通过连接到该命名管道来从应用程序编写最终协议。 (U可以实现一个小型数据库像一样)

的WinSock:(如果你有更多的进程数不要使用,因为你需要发送端请求到其他进程要么进程应该绑定到你的应用程序。或者它应该在端口中侦听)。

创建文件/数据库:在进程之间共享文件。 (如果你需要,你可以有多个文件)。在阅读或写作之前进行锁定。

+0

谢谢。一切似乎都是有效的,但仍然对我来说都是过度的伤害。也许我想太多(/太少)? – parrowdice

+0

如果你正在寻找Windows应用程序API(如桌面应用程序),你可以使用** SendMessage **。例如:YourProcess [] = Process.GetProcessesByName(“testProcess.exe”); SendMessage(YourProcess [1] .MainWindowHandle,CLOSE_APP_PROTOCOL,NULL,NULL); ' 您将在您的testProcess中收到CLOSE_APP_PROTOCOL。 – ban

+0

1.这看起来不像C++,但它确实证明了你的意图。 2.关闭进程信号不是问题,我们可以使用SetEvent。 3.我们不知道命令行进程中的进程名称或句柄 – parrowdice

1

我会考虑使用两个物体的溶液:

  • 共享信号对象,由主(控制器产生的?)的应用程序,为0的初始计数,只是请求其他进程终止(调用SetEvent())之前 - 我假定其他进程不创建此事件的对象,无论是如果它尚未创建他们失败了。
  • 一个互斥对象,通过其他的(孩子?)创建的进程,不是用于等待,但允许主进程检查其存在(如果所有的子进程终止它应该被销毁)。互斥对象具有可以由多个进程“创建”的区别(根据文档)。

同步情况如下:

  • 在初始化子进程应该创建互斥对象(设置的初始所有权FALSE)。
  • 在接收到终止请求应当由一个(ReleaseSemaphore()),然后退出正常增加信号计数的子进程。
  • 主要进程将进入一个循环的信号调用WaitForSingleObject()有合理的小超时(例如,大约250毫秒),然后检查不是对象是否被授予或出现超时,但互斥量是否仍然存在 - 如果不,这意味着所有的子进程都被终止。

这样的设置使得避免进程间通信方案(例如,具有子进程通信的把手回 - 其数量不明反正),虽然它不是严格意义上讲“轮询”两种。好吧,有一些超时涉及(有些人可能会认为这仅仅是轮询),但检查也是在每个进程报告它正在终止之后执行的(您可以使用一些跟踪来查看超时实际已经过了多少次) 。

+0

我不认为这比简单的轮询更好,因为当最后一个下级进程调用'ReleaseSemaphore'时,互斥量仍然存在。所以你总是要等待超时发生,而且你可能只是在一个循环中睡250毫秒。 –

1

简单的方法:你已经有了,每一个下属进程打开了一个事件对象,所以你可以使用它。在主进程中设置事件后,关闭句柄,然后进行轮询,直到发现事件对象不再存在。

更好的方法:命名管道作为同步对象,如已经建议。 听起来很复杂,但事实并非如此。

这个想法是,每个下级进程在启动时创建一个命名管道的实例(即所有名称都相同)。不需要监听线程,或者根本不需要任何I/O逻辑;你只需要使用CreateNamedPipe创建实例,然后扔掉手柄而不关闭它。当进程退出时,手柄会自动关闭,这就是我们所需要的。

要查看是否有任何从属进程,主进程将尝试连接到使用CreateFile该命名管道。如果它没有找到文件错误,则没有下级进程,所以我们完成了。

如果连接成功,至少有一个下级进程需要等待。 (当您尝试连接到具有多个可用实例的命名管道时,Windows会选择将哪个实例连接到它,它与哪个实例无关。)

主进程然后会调用ReadFile (只是一个简单的同步读取,一个字节会做)并等待它失败。一旦你确认了错误代码是ERROR_BROKEN_PIPE(这将是,除非有什么严重错误),你知道有问题的从属进程已经退出。然后,您可以循环并尝试其他连接,直到不再有下级进程。 (我假设用户在一个或多个下属挂起时必须进行干预,如果需要的话,跟踪进程ID并以编程方式执行某些操作并不是不可能的,但它并不完全微不足道,应该是一个单独的问题。)

+0

这听起来像是这样做的方式。我会沿着这条路线走下去,并接受答案。想不到任何原因。感谢您花时间回答:) – parrowdice

+0

无后顾之忧。你可以在我的Stack Overflow配置文件中找到我的电子邮件地址,如果你发现这不能按预期工作,我很乐意看看[mcve]。 –