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

时间:2017-01-19 13:43:31

标签: c++ winapi synchronization

情景:

计算机上运行多个进程。名称和句柄未知,但它们都有一段代码在我们手中运行。

运行命令行进程。它向其他进程发出信号通知他们需要结束(SetEvent),我们的代码在其他进程中选择并处理。

目标:

命令行进程需要等待,直到其他进程结束。如何实现这一目标?

所有想到的就是设置一些共享内存或其他东西并让每个进程将其句柄写入其中,以便命令行进程可以等待它们,但这对于它来说似乎是多么努力是。必须有一些可以等待的内核级别引用计数吗?

修改1:

我想可能将进程分配给作业对象,然后命令行进程可以等待吗?虽然不太理想......

编辑2:

无法使用作业对象,因为它会干扰使用作业的其他内容。所以现在我认为进程将获得某个/任何同步对象(信号量,事件等)的句柄,并且命令行进程将轮询它的存在。它必须进行轮询,好像等待它会使对象保持活着状态。当进程死亡时,同步对象被窗口清理,因此下一次轮询将指示没有进程。这不是一个很好的,最干净的方法,但对于它需要做的工作来说足够简单。有什么进步吗?

3 个答案:

答案 0 :(得分:2)

您可以执行以下任一方式。

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

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

WinSock :(如果您有更多进程,请不要使用。因为您需要将结束请求发送到其他进程。要么进程应该绑定到您的应用程序,要么应该在端口。)

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

答案 1 :(得分:1)

我会考虑使用两个对象的解决方案:

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

同步如下:

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

这种设置避免了进行进程间通信方案(例如让子进程回传它们的句柄 - 无论如何都是未知的),而严格来说也不是“轮询”。好吧,有一些超时(有些人可能会争辩说这只是轮询),但是在每个进程报告它正在终止之后也会执行检查(你可以使用一些跟踪来查看实际超时的超时次数)

答案 2 :(得分:1)

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

更好的方法:命名管道作为同步对象,如已建议的那样。 听起来很复杂,但不是。

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

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

如果连接成功,我们需要等待至少一个从属流程。 (当您尝试连接到具有多个可用实例的命名管道时,Windows会选择将您连接到哪个实例。对我们来说它不重要。)

然后主进程将调用ReadFile(只是一个简单的同步读取,一个字节将执行)并等待它失败。一旦您确认错误代码为ERROR_BROKEN_PIPE(除非出现严重错误),您就会知道相关的从属流程已退出。然后,您可以循环并尝试另一个连接,直到不再有从属进程。

(我假设如果一个或多个下属已经挂起,用户将不得不进行干预。如果可取的话,不可能跟踪进程ID并以编程方式执行某些操作,但是它并非完全无关紧要,应该是一个单独的问题。)