源代码:
static void *cmd_exec_thread_handler(void *arg)
{
pthread_cleanup_push(thread_exit_handler, arg);
cmd_base_t *cmd_base = (cmd_base_t *)arg;
printf("fork process\n");
fflush(stdout);
pid_t pid = fork();
if (pid < 0) {
perror("fork process error");
printf("for process error");
fflush(stdout);
}
else if (pid == 0) {
printf("for clild process ok");
fflush(stdout);
cmd_base->pid = getpid();
// log_debug("----------> start process(pid: %d)\n", cmd_base->pid);
execlp("bash", "bash", "-c", cmd_base->cmd, NULL);
}
else if (pid > 0) {
cmd_base->pid = pid;
int status = 0;
log_info("------------> wait pid (%d)\n", cmd_base->pid);
waitpid(cmd_base->pid, &status, WUNTRACED); // 等待进程结束
if (WIFEXITED(status)) {
log_debug("waitpid process exit OK\n");
}
else if (WEXITSTATUS(status)) {
log_debug("waitpid process exit: %d\n", WEXITSTATUS(status));
}
else if (WIFSIGNALED(status)) {
log_debug("waitpid process exit by signal(%s) of process(pid: %d)\n", sys_siglist[(WTERMSIG(status))], getpid());
}
else if (WCOREDUMP(status)) {
log_debug("waitpid process exit by coredump error\n");
}
}
log_debug("----------> cmd: %s is over (pid: %d)\n", cmd_base->cmd, cmd_base->pid);
cmd_base->pid = -1;
cmd_base->run = false;
pthread_cleanup_pop(1);
return NULL;
}
上面的函数是一个线程执行函数,调用这个函数,execlp有概率会出现阻塞的情况。
网上翻了一下资料参考链接,造成这个的原因是产生了死锁。
因为我使用了自己的日志库,日志库里面有互斥锁用来保证输入数据的一致性。
当父进程中的线程有调用日志打印函数时,会对互斥锁上锁,在还未解锁的情况,如果这时刚好fork子进程成功,并在子进程中执行日志打印函数的话,这个时候就会发生上面的所说的情况。
vfork
代替fork
。子进程不从父进程中继承锁。(此时,没有再出现过问题。但是不推荐使用vfork)exec
外,不要再干其它事情,比如输出日志。尽量不要有关于锁的操作。