簡體   English   中英

線程和派生:從popen()-pipe讀取時,fgetc()會阻塞

[英]Threads and fork: fgetc() blocks when reading from popen()-pipe

在多線程程序(在ARM上運行)中,我有

一個主線程 ,除其他外,該線程定期使用popen( "pidof -s prog" )是否正在運行另一個程序。 我使用O_CLOEXEC標志作為文件描述符,並檢查fgetc()是否從管道接收到任何東西。 將文件描述符設置為“非阻塞”將導致不讀取任何內容,也無濟於事 與shell命令相同的pidof命令執行得很好。

在另一個線程中 ,每當發生特定事件時,使用子進程中具有直接execl() fork()即可啟動rsync操作。 父母使用信號處理程序來觀察孩子的狀態,並可以選擇在另一個特定事件中殺死孩子。 我是否使用rsyncsleep調用exec()都沒有關系-結果是相同的。

問題在於,主線程中的fgetc()阻塞,直到子進程終止。

我將盡早通過fork()解決這個問題(在我開始撰寫的另一篇文章中 ,應用程序是單線程的)。

但無論如何:

我想了解是什么導致fgetc()從管道讀取時阻塞。

到目前為止,我已經嘗試了一些方法:

  • 我試圖通過一個小型示例應用程序來重現該問題,該示例應用程序執行了上述操作,並希望它能夠顯示相同的錯誤行為,但不幸的是,它可以正常工作,這就是為什么我現在未提供任何代碼的原因。 也許我錯過了相關要點。
  • 通過system()使用相同的rsync調用不會引起任何問題
  • 我看過一個system() 實現 ,可以看到在fork()之前對信號進行了處理:

    • SIGCHLD被阻止
    • SIGINT和SIGQUIT被忽略

    我需要SIGCHLD的信號處理程序,但是出於好奇,我試圖與上面的代碼相同(我將sigprocmask()替換為pthread_sigmask() )-沒有成功,行為保持不變。

    我的BSP隨附的源代碼中找不到system()任何實現。

該程序通過fstream打開其他文件-並且沒有O_CLOEXEC( 更改它會有點麻煩

錯誤修正和意外行為的解釋

確實,我已經錯過了相關的要點。 在使示例程序更適合原始代碼示例之后,我看到了信號處理程序(在測試程序中工作)的問題。 摘抄:

void MyClass::sig_handler(int sig) {
    if( m_pid < 1 ) // not the child we're waiting for
        return;

    pid_t pid;
    int wstatus;

    while ((pid = waitpid( -1, &wstatus, WNOHANG )) != -1 ) {
        // error: this returns 0 as long as any children are alive
        // -> check for "> 0" to ignore active child processes
        if( pid != m_pid )
            return;
        // handle stuff here...
    }
}

我不得不替換以下行

while ((pid = waitpid( -1, &wstatus, WNOHANG )) != -1 )

while ((pid = waitpid( -1, &wstatus, WNOHANG )) > 0 )

因為該程序的其他線程fork()子級(例如,帶有popen() )。 如果這些終止,則也會調用信號處理程序(靜態類函數)。

我認為:

在調用fork()的線程中,我使用具有默認值和重置值-1的成員m_pid 它從fork()獲取pid。 如果m_pid為-1,則sig處理程序立即返回。

擋在程序popen()其中fork() S(可以是任何其它調用fork()多個)。 因此,當popen()返回時,將輸入SIGCHLD的信號處理程序。 m_pid的檢查在調用m_pid = fork()通過。 waitpid()不會返回-1,而是popen()子代的pid,然后繼續檢查返回值= 0,直到所有子代都終止為止-我正在等待的子代仍然存在! 只有waitpid()返回-1 ,主線程才能繼續使用fgetc()讀取。

waitpid頁:

如果指定了WNOHANG,並且存在由pid指定的一個或多個孩子,但尚未更改狀態,則返回0。 錯誤時,返回-1

因為sig處理程序檢查m_pid != -1 ,所以僅當我在MyClass中使用fork()設置m_pid時才出現問題。

這就是為什么使用system()不會引起問題的原因。 m_pid未設置為一個值!= -1,如果如一個孩子因此SIG處理程序后立即返回popen()版在主線程。

模仿 system()調用失敗,因為我將m_pid設置為fork() ,因此sig處理程序沒有立即返回。

我猜因為sig處理程序是一個static member function ,因此該處理程序會阻塞fork()創建子進程的那個線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM