【发布时间】:2015-01-26 21:38:07
【问题描述】:
我的程序在等待子进程 (gzip) 完成时遇到问题,并且需要很长时间才能完成。
在它开始等待之前,它会关闭gzip 的输入流,所以这应该会触发它很快终止。我检查了系统,gzip 没有消耗任何 CPU 或等待 IO(写入磁盘)。
非常奇怪的是它停止等待的时间......
我们在内部使用 pthreads 的程序。它并排处理 4 个 pthread。每个线程处理许多工作单元,对于每个工作单元,它启动一个新的gzip 进程(使用fork() 和execve())来写入结果。当gzip 没有终止时线程挂起,但是当其他线程关闭它们的实例时它突然终止。
为了清楚起见,我正在设置一个管道:my program(pthread) --> gzip --> file.gz
我想这可以部分解释为 CPU 负载。但是当进程间隔几分钟启动并且整个系统由于这个锁定问题而最终只使用 4 个核心时,这似乎不太可能。
启动gzip 的代码如下。调用execPipeProcess 以便孩子直接写入文件,但从我的程序中读取。那就是:
execPipeProcess(&process, "gzip", -1, gzFileFd)
有什么建议吗?
typedef struct {
int processID;
const char * command;
int stdin;
int stdout;
} ChildProcess;
void closeAndWait(ChildProcess * process) {
if (process->stdin >= 0) {
stdLog("Closing post process stdin");
if (close(process->stdin)) {
exitError(-1,errno, "Failed to close stdin for %s", process->command);
}
}
if (process->stdout >= 0) {
stdLog("Closing post process stdin");
if (close(process->stdout)) {
exitError(-1,errno, "Failed to close stdout for %s", process->command);
}
}
int status;
stdLog("waiting on post process %d", process->processID);
if (waitpid(process->processID, &status, 0) == -1) {
exitError(-1, errno, "Could not wait for %s", process->command);
}
stdLog("post process finished");
if (!WIFEXITED(status)) exitError(-1, 0, "Command did not exit properly %s", process->command);
if (WEXITSTATUS(status)) exitError(-1, 0, "Command %s returned %d not 0", process->command, WEXITSTATUS(status));
process->processID = 0;
}
void execPipeProcess(ChildProcess * process, const char* szCommand, int in, int out) {
// Expand any args
wordexp_t words;
if (wordexp (szCommand, &words, 0)) exitError(-1, 0, "Could not expand command %s\n", szCommand);
// Runs the command
char nChar;
int nResult;
if (in < 0) {
int aStdinPipe[2];
if (pipe(aStdinPipe) < 0) {
exitError(-1, errno, "allocating pipe for child input redirect failed");
}
process->stdin = aStdinPipe[PIPE_WRITE];
in = aStdinPipe[PIPE_READ];
}
else {
process->stdin = -1;
}
if (out < 0) {
int aStdoutPipe[2];
if (pipe(aStdoutPipe) < 0) {
exitError(-1, errno, "allocating pipe for child input redirect failed");
}
process->stdout = aStdoutPipe[PIPE_READ];
out = aStdoutPipe[PIPE_WRITE];
}
else {
process->stdout = -1;
}
process->processID = fork();
if (0 == process->processID) {
// child continues here
// these are for use by parent only
if (process->stdin >= 0) close(process->stdin);
if (process->stdout >= 0) close(process->stdout);
// redirect stdin
if (STDIN_FILENO != in) {
if (dup2(in, STDIN_FILENO) == -1) {
exitError(-1, errno, "redirecting stdin failed");
}
close(in);
}
// redirect stdout
if (STDOUT_FILENO != out) {
if (dup2(out, STDOUT_FILENO) == -1) {
exitError(-1, errno, "redirecting stdout failed");
}
close(out);
}
// we're done with these; they've been duplicated to STDIN and STDOUT
// run child process image
// replace this with any exec* function find easier to use ("man exec")
nResult = execvp(words.we_wordv[0], words.we_wordv);
// if we get here at all, an error occurred, but we are in the child
// process, so just exit
exitError(-1, errno, "could not run %s", szCommand);
} else if (process->processID > 0) {
wordfree(&words);
// parent continues here
// close unused file descriptors, these are for child only
close(in);
close(out);
process->command = szCommand;
} else {
exitError(-1,errno, "Failed to fork");
}
}
【问题讨论】:
-
也许你正在耗尽进程限制或类似的东西?
-
不在 4 pthreads + 4 procecsses 我不是。不过谢谢你的建议。我已经通过调试器检查了这一点,它在等待时停止,而不是在 fork 上。无论如何感谢您的建议。
-
“每个线程处理许多工作单元,并且对于每个工作单元,它都会启动一个新的 gzip 进程”每个 what ??每一个什么?线程还是“多个工作单元”?而在 pthread 多线程应用程序中间的
fork()-ing 并不完全可取。 See here。它是可行的,但你必须小心。 -
抱歉...每个工作单元都有自己的 gzip 进程,每个线程有很多 gzip 进程,但每个线程只能同时有一个。
-
请注意,如果
in == STDIN_FILENO和/或out == STDOUT_FILENO,则可能不是您希望孩子这样做:“close(in); close(out);”。