2013-10-21 79 views
2

我試圖用叉子來使用類似的代碼是從多線程的父執子計劃:使用管道在多線程程序與孩子溝通

#include <thread> 
#include <unistd.h> 
#include <vector> 
#include <sys/wait.h> 

void printWithCat(const std::string& data) { 
    std::vector<char*> commandLine; 
    // exec won't change argument so safe cast 
    commandLine.push_back(const_cast<char*>("cat")); 
    commandLine.push_back(0); 

    int pipes[2]; 
    pipe(pipes); 
    // Race condition here 
    pid_t pid = fork(); 
    if (pid == 0) { 
     // Redirect pipes[0] to stdin 
     close(pipes[1]); 
     close(0); 
     dup(pipes[0]); 
     close(pipes[0]); 
     execvp("cat", &commandLine.front()); 
    } 
    else { 
     close(pipes[0]); 
     write(pipes[1], (void*)(data.data()), data.size()); 
     close(pipes[1]); 
     waitpid(pid, NULL, 0); 
    } 

} 

int main() 
{ 
    std::thread t1(printWithCat, "Hello, "); 
    std::thread t2(printWithCat, "World!"); 

    t1.join(); 
    t2.join(); 
} 

此代碼包含調用之間的競爭條件,以管對叉子的呼叫。如果兩個線程都創建了管道然後fork,那麼每個子進程都包含對兩個管道的打開文件描述符,並且只關閉一個。結果是管道永遠不會關閉,子進程永遠不會退出。我目前將管道和fork調用包裝在一個全局鎖中,但是這增加了一個額外的同步。有沒有更好的辦法?

+1

你肯定有一個競爭條件?管道是一個局部變量,所以每個線程都有自己的副本。 – paj28

+3

管道是本地的,但打開的文件描述符對進程是全局的。只有當所有打開的描述符關閉時,管道纔會關閉,並且叉可能無意中創建您不瞭解的描述符的副本。 –

+1

我看到問題,我不知道更好的解決方案。分叉和線程不能很好地協同工作,至今我還沒有聽到任何解決方案。 –

回答

1

不要以爲你通過避免代碼中的鎖定來避免同步 - 無論如何,內核將爲進程創建鎖定,可能比鎖定更爲全球化。

因此,請繼續並在此處使用輕量級互斥鎖。

你的問題將要出現時,程序的不同部分使fork調用,並且不會在單個互斥同意(因爲有些埋在庫代碼等)

+0

對於缺乏更好的想法,我會接受這個答案。一些Unix的版本有/產生一個版本的產卵,這正是我所需要的,但它不是標準的。 http://support.sas.com/documentation/onlinedoc/sasc/doc700/html/lr2/zid-9275.htm –