在研究通过使用vfork()而不是fork()来改进Recoll性能的可能性时,我遇到了fork()问题,这是我无法解释的。在fork和exec块之间运行的线程其他线程读取
Recoll重复执行外部命令来翻译文件,这就是示例程序的作用:它启动重复执行“ls”并读回输出的线程。
以下问题不是“真正的”问题,因为实际的程序不会触发问题。我只是偶然看到fork()/ vfork()和exec()之间的线程是停止还是停止。
当我有一个fork()和exec()之间的busy-looping线程时,另一个线程永远不会完成数据读取:最后一个read()应该指示eof永远被阻塞或者直到另一个线程的循环结束(在这一点上,一切恢复正常,你可以通过用一个完成的循环代替无限循环来看到)。当read()被阻塞时,“ls”命令已经退出(ps显示<不存在>,一个僵尸)。
这个问题有一个随机的方面,但示例程序大部分时间“成功”。我测试了Linux内核3.2.0(Debian),3.13.0(Ubuntu)和3.19(Ubuntu)。在虚拟机上工作,但你至少需要2个过程,我不能使它与一个处理器一起工作。
下面是示例程序,我看不出我做错了什么。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <iostream>
using namespace std;
struct thread_arg {
int tnum;
int loopcount;
const char *cmd;
};
void* task(void *rarg)
{
struct thread_arg *arg = (struct thread_arg *)rarg;
const char *cmd = arg->cmd;
for (int i = 0; i < arg->loopcount; i++) {
pid_t pid;
int pipefd[2];
if (pipe(pipefd)) {
perror("pipe");
exit(1);
}
pid = fork();
if (pid) {
cerr << "Thread " << arg->tnum << " parent " << endl;
if (pid < 0) {
perror("fork");
exit(1);
}
} else {
// Child code. Either exec ls or loop (thread 1)
if (arg->tnum == 1) {
cerr << "Thread " << arg->tnum << " looping" <<endl;
for (;;);
//for (int cc = 0; cc < 1000 * 1000 * 1000; cc++);
} else {
cerr << "Thread " << arg->tnum << " child" <<endl;
}
close(pipefd[0]);
if (pipefd[1] != 1) {
dup2(pipefd[1], 1);
close(pipefd[1]);
}
cerr << "Thread " << arg->tnum << " child calling exec" <<
endl;
execlp(cmd, cmd, NULL);
perror("execlp");
_exit(255);
}
// Parent closes write side of pipe
close(pipefd[1]);
int ntot = 0, nread;
char buf[1000];
while ((nread = read(pipefd[0], buf, 1000)) > 0) {
ntot += nread;
cerr << "Thread " << arg->tnum << " nread " << nread << endl;
}
cerr << "Total " << ntot << endl;
close(pipefd[0]);
int status;
cerr << "Thread " << arg->tnum << " waiting for process " << pid
<< endl;
if (waitpid(pid, &status, 0) != -1) {
if (status) {
cerr << "Child exited with status " << status << endl;
}
} else {
perror("waitpid");
}
}
return 0;
}
int main(int, char **)
{
int loopcount = 5;
const char *cmd = "ls";
cerr << "cmd [" << cmd << "]" << " loopcount " << loopcount << endl;
const int nthreads = 2;
pthread_t threads[nthreads];
for (int i = 0; i < nthreads; i++) {
struct thread_arg *arg = new struct thread_arg;
arg->tnum = i;
arg->loopcount = loopcount;
arg->cmd = cmd;
int err;
if ((err = pthread_create(&threads[i], 0, task, arg))) {
cerr << "pthread_create failed, err " << err << endl;
exit(1);
}
}
void *status;
for (int i = 0; i < nthreads; i++) {
pthread_join(threads[i], &status);
if (status) {
cerr << "pthread_join: " << status << endl;
exit(1);
}
}
}
我喜欢解决你的难题:) – Celada