多线程中fork的坑

8人阅读 评论(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函数,因为我的想法是让父进程阻塞等待子进程的编译和运行情况。
问题就出现在这里

由于我是在线程中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很简单,但是发现问题所在才是需要耐心和能力的。

查看评论

VC6.0中如何改变对话框的背景颜色

黄基前(广西桂林)---- 笔者曾在《软件报》2000年第5期中讨论过如何改变控件的颜色,但还有相当一部分的读者来信提问:一个基于对话框的MFC AppWizard应用程序中,如何改变对话框的背景颜色...
  • nm
  • nm
  • 2000-08-16 10:26:00
  • 3358

并行处理:分叉(fork)和线程(thread)

        并行处理:分叉(fork)和线程(thread)        分叉(fork)是UNIX术语,当分叉一个进程(一个运行的程序)时,基本上是复制了它,并且分叉后的两个进程都从当...
  • iw1210
  • iw1210
  • 2016-05-10 17:06:06
  • 2091

【Linux】利用fork()创建多个线程

在《【Linux】fork()》(点击打开链接)只是简单交代了如同利用fork()创建子线程的方法,实际是更应该说将一个程序一分为二的方法。还有很多事情隐藏在其中值得细致思考。由于fork()结构的特...
  • yongh701
  • yongh701
  • 2016-12-19 17:35:37
  • 1328

谨慎使用多线程中的fork

前言 在单核时代,大家所编写的程序都是单进程/单线程程序。随着计算机硬件技术的发展,进入了多核时代后,为了降低响应时间,重复充分利用多核cpu的资源,使用多进程编程的手段逐渐被人们接受和掌握。然而因...
  • fivedoumi
  • fivedoumi
  • 2016-08-12 16:04:29
  • 459

每天进步一点点——论fork()函数与Linux中的多线程编程

fork()函数的调用会导致在子进程中除调用线程外的其它线程全都终止执行并消失,因此在多线程的情况下会导致死锁和内存泄露的情况。在进行多线程编程的时候尽量避免fork()的调用,同时在程序在进入mai...
  • cywosp
  • cywosp
  • 2014-05-28 10:49:52
  • 30511

多线程与fork

前言:exce调用并不创建新进程,所以前后的进程ID并未改变,exec只是用一个全新的程序替换了当前进程的正文、数据、堆和栈段 多线程程序里不准使用fork :为什么??? UNIX上C++程序设...
  • anxuegang
  • anxuegang
  • 2011-08-04 00:06:01
  • 7976

多线程程序中的fork调用

多线程程序执行fork调用是一个比较复杂的问题。首先fork调用的行为大概是复制一个和父进程一样的子进程,然后两个进程以不同的值返回。理论上,父子进程应该是非常相似的。fork调用在单线程上是非常容易...
  • cqu20093154
  • cqu20093154
  • 2014-11-24 12:57:43
  • 988

fork与线程的关系

最近在想,如果一个进程在运行时启动了多个线程,这个时候再fork一下,会不会把多个线程也同时fork出来了?毛主席说的好“实践是检验真理的唯一标准”,来写个测试代码测试一下 class CTestTh...
  • hxfxjun
  • hxfxjun
  • 2008-06-23 23:18:00
  • 117

多线程程序与fork()分析

我们在编写服务器程序时,要么使用多线程,要么使用多进程。如果我们在多线程程序中使用了fork(),这会带来很多不必要的麻烦,甚至带来死锁。 示例: #include #include #inc...
  • FreeeLinux
  • FreeeLinux
  • 2016-12-01 22:30:24
  • 523

线程和fork-

关键接口: pthread_atfork(void (*prepare)(void),void (*parent)(void), void(*child)(void))重点内容 pthread_a...
  • u014325402
  • u014325402
  • 2017-10-22 23:12:13
  • 52
    个人资料
    持之以恒
    等级:
    访问量: 781
    积分: 143
    排名: 116万+