我正在尝试使用fork从多线程父级执行子程序,使用类似于:
的代码#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,则每个子进程都包含两个管道的打开文件描述符,只关闭一个。结果是管道永远不会关闭,子进程永远不会退出。我目前将管道和fork调用包装在全局锁中,但这会增加一个额外的同步。还有更好的方法吗?
答案 0 :(得分:1)
不要以为通过避免代码中的锁来避免同步 - 内核无论如何都会锁定进程创建,可能在比锁定更全局的范围内。
所以请继续使用轻量级互斥锁。
当程序的不同部分进行fork
调用并且不同意单个互斥锁时(因为某些部分隐藏在库代码中等),您的问题将会出现