2013-10-21 53 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 –