多核心下 QProcess 與系統調用的互動

QProcess 在呼叫 start 之後會註冊 SIGCHLD,用來知道子行程已經結束了。在多核心下,如果啟動了一個新的 QProcess 之後,沒有用 waitForFinished() 等待它結束的話,接下來如果執行了系統調用,如 read/write,則此系統調用可能會失敗,回傳值 -1,errno 為 EINTR。

基本分析是這樣。子行程跑在核心二,父行程在核心一。父行程因為註冊了 SIGCHLD,所以當在執行系統調用時子行程結束了,其 SIGCHLD 就會發向父行程,導至系統調用返回。

解決的方式第一個當然是使用 QProcess 時要確定有先執行 waitForFinished 再做事(如果是要啟動一個 daemon,應該用 startDetached 而不是用 start。前者不會註冊 SIGCHLD)。另一個方式是在做系統調用的時候,可以使用 GNU 下的 TEMP_FAILURE_RETRY macro。這個 macro 會判斷執行結果是不是 -1 且 errno 是 EINTR,如果是的話就重新執行。

由於註冊 SIGCHLD 是在產生 QProcess 的那個執行緒,其它執行緒預設都是忽略。所以其它正在使用系統調用的執行緒,SIGCHLD 應該不會產生影響。

Signal 是發給 process 而非特定執行緒,只要有註冊該 signal 的執行緒都有可能收到,但是不能確定是哪一個(可能是最閒的那一個)。故在 main 註冊 signal 的話,所有接下來由 main 產生的執行緒都會繼承 main 的 signal mask。

如果只想要某一個執行緒收到 signal 的話,一個方式是在 main 先註冊 signal,然後建立這個要處理 signal 的執行緒。接著 main 在產生其它執行緒前,先將所有的 signal mask 掉不處理。

留言

熱門文章