2017-01-19 91 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]。 –