多核心下 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 掉不處理。
基本分析是這樣。子行程跑在核心二,父行程在核心一。父行程因為註冊了 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 掉不處理。
留言
張貼留言