美文网首页
多线程中fork的坑

多线程中fork的坑

作者: _codelover | 来源:发表于2018-05-10 17:40 被阅读0次

多线程中fork的坑


问题所在

在写oj的时候,由于使用了线程池,并且在获取用户程序运行结果的时候使用的是管道进行子进程的标准输出的获取,
最后带来了一个问题,就是发现本来线程池有5个任务,最后调试信息的打印确没有5个,而且个数不确定。

初步怀疑

是不是线程池出现了死锁的情况。

添加线程池任务

    void addTask(clTask* newTask)
    {
        pthread_mutex_lock(&pthreadMutex);
        allTask.push(newTask);
        pthread_mutex_unlock(&pthreadMutex);
        pthread_cond_broadcast(&pthreadCond);
    }

线程主函数

void* clPthread::pthreadMain(void *arg)
{
    clPthread& self = *(clPthread*)arg;
    while(1)
    {
        pthread_mutex_lock(&(self.pthreadMutex));
        while(0 == self.allTask.size())
        {
            //阻塞在条件变量上并且解锁互斥锁
            pthread_cond_wait(&(self.pthreadCond),&(self.pthreadMutex));
            //条件变量满足后,加锁
        }
        clTask* dealTask = self.allTask.front();
        self.allTask.pop();
        self.dealTask.push(dealTask);

        pthread_mutex_unlock(&(self.pthreadMutex));
        dealTask->run();
    }
}

这是很标准的的生产者消费者模型了,应该不会出现死锁的情况。但还是怀疑,所以后来我在每次线程池运行的任务的地方打印调试信息,
发现任务是都执行了的,并且是5次,并没有出现死锁的情况。那么问题可能出现在下面的代码中了。

找到问题

再往下面走就是编译和运行的函数了,oj的编译和运行我是采用fork进程然后重定向子进程的标准输出来获取用户程序的编译错误信息和
运行情况的,获取子进程状态和回收子进程使用的是wait函数,至于为什么使用wait函数,因为我的想法是让父进程阻塞等待子进程的编译和运行情况。
<b>问题就出现在这里</b>:

由于我是在线程中fork的子进程,子进程结束的时候会触发wait函数
但是此时的wait函数的触发其实不一定是之前的线程fork的子进程触发的,可能是其他线程fork的子进程,因为所有线程fork的子进程的ppid都一样
等于是所有的子进程结束都会使得wait苏醒,但是这个wait确不是应该苏醒的那一个。

void clCompiler::compile()
{
    int fd[2];
    int ret = pipe(fd);
    int res;
    pid_t pid;
    chdir(workDir.c_str());
    solution->prepareCode();
    pid = fork();
    if(pid > 0){
        char buf[1024];
        close(fd[1]);
        //问题所在的地方
        wait(&res);
        read(fd[0],buf,sizeof(buf));
        close(fd[0]);
        if(res == 0){
            //编译成功
            this->status = COMPLIE_OK;

        } else{
            //编译失败
            this->status = COMPLIE_ERROR;
        }
        this->complieError = buf;
    }else {
        //查看ppid都是同一个
        printf("ppid:%d\n",getppid());
        close(fd[0]);
        dup2(fd[1], STDOUT_FILENO);
        dup2(fd[1], STDERR_FILENO);

        this->doCompile();
        close(fd[1]);
        exit(0);
    }
}

如何解决

既然找到问题了,那么解决也不是很难了,只需要使用函数waitpid指定要回收的进程id就行。

虽然修改一个bug很简单,但是发现问题所在才是需要耐心和能力的。

相关文章

  • 多线程中fork的坑

    多线程中fork的坑 问题所在 在写oj的时候,由于使用了线程池,并且在获取用户程序运行结果的时候使用的是管道进行...

  • (三)线程的并发工具类

    Fork-Join java 下多线程的开发可以我们自己启用多线程,线程池,还可以使用fork-join ,for...

  • 深入探讨pcntl_fork函数

    上次“闲言之PHP不支持多线程”时,提到了PHP的原生fork进程函数pcntl_fork,其手册中官方文档介绍如...

  • 分而治之—Fork-Join

    Fork-Join java下多线程的开发可以我们自己启用多线程,线程池,还可以使用forkjoin,forkjo...

  • 线程的并发工具类 --- Fork-Join

    Fork-Join java下多线程的开发可以我们自己启用多线程,线程池,还可以使用forkjoin, forkj...

  • 2、线程的并发工具类

    Fork-Join java下多线程的开发可以我们自己启用多线程,线程池,还可以使用forkjoin, forkj...

  • 线程的并发工具类

    Java 下多线程的开发我们可以自己启用多线程,线程池,除此之外,Java还为我们提供了Fork-Join、Cou...

  • fork() 函数与 Linux 中的多线程编程

    一、fork()函数 在操作系统的基本概念中进程是程序的一次执行,且是拥有资源的最小单位和调度单位(在引入线程的操...

  • Qt多线程编程爬坑笔记

    最近在工作中用到了Qt中的多线程,踩了不少坑,故作下笔记,警示后人 - -! Overview 使用多线程编程可以...

  • linux中fork()函数详解 (阅读笔记)

    linux中fork()函数详解(转载) 一、fork入门知识 在Linux中fork函数是非常重要的函数,它的作...

网友评论

      本文标题:多线程中fork的坑

      本文链接:https://www.haomeiwen.com/subject/zirtdftx.html