在Windows上,您不能直接与Process ID通信或交互。而是,进程ID的作用类似于正在运行的进程的“文件名”。如果要与流程进行交互,请“打开”它,这将为您提供一个句柄。此句柄在其生命周期内与进程永久关联,就像文件描述符与给定文件永久关联一样,即使您在文件系统节点打开时也对其进行了操作。另外,句柄还充当内核同步对象,特别是事件对象。当进程退出时,将通知该事件。可以在WaitForSingleObject
之类的OS调用中使用该句柄,它们会阻塞线程直到事件发生。这意味着两件事:
您可以等待进程退出,并且该线程被完全阻塞并且在事件发生之前不安排执行。
一旦您具有处理流程,无论PID重用如何,它都会始终引用特定的流程。成功打开它后,您将被锁定在该过程中。
在UNIX系统上,我能够找到等待不相关进程退出的最佳方法是轮询循环,该轮询循环每 n 毫秒(其中 n 通常是500或1000)。观察者注意到,当PID不再收到信号时,该过程已退出。这意味着在观察者通知之前,它可能长达一个完整的时间间隔,并且如果在此时间间隔内另一个进程以相同的PID启动,那么它会错误地继续监视,而在不知不觉中切换为监视新过程。 (也许有些东西可以在短时间内阻止PID重复使用,以精确地缓解此问题?不过,我找不到类似本文所述的任何东西。)
甚至tail --pid
都以这种方式工作。
在UNIX系统(或也许是某些特定的UNIX-y内核)上,是否有任何方法可以可靠地等待进程退出,而无需轮询等待时间或PID重用的风险(尽管通常很小) ?
我在Linux系统上对/proc/$PID/fd
中的文件描述符做了一些实验。我希望stdout
可能在进程退出时关闭。但是,该进程似乎继承了其父流。因此,从中读取不仅会干扰程序的常规操作,而且在进程退出时,如果父进程仍然打开了相同的stdout
,那么即使/proc/$PID/fd
消失了,句柄也会打开从它继续指向有效的内核对象。如果我在一个终端上运行程序,并且cat /proc/$PID/fd/1
,则cat
会窃取该程序的输出。但是,当该程序退出时,cat
继续运行,现在从父进程(例如shell)窃取了输出。 cat
仅在整个终端关闭后才退出。这个想法太重要了!