【发布时间】:2018-03-01 12:04:54
【问题描述】:
我想明白他们在这里的意思。为什么这个程序会“挂起”?
来自https://bisqwit.iki.fi/story/howto/openmp/
OpenMP 和
fork()值得一提的是,在一个 调用fork()的程序需要特别考虑。这 问题只影响 GCC; ICC 不受影响。如果你的程序 打算成为使用daemonize()或其他的后台进程 类似的意思是,你一定不能在fork 之前使用OpenMP 功能。 使用 OpenMP 功能后,只有在以下情况下才允许分叉 子进程不使用 OpenMP 功能,或者它作为一个 全新的流程(如exec()之后)。这是一个错误程序的示例:
#include <stdio.h> #include <sys/wait.h> #include <unistd.h> void a(){ #pragma omp parallel num_threads(2) { puts("para_a"); // output twice } puts("a ended"); // output once } void b(){ #pragma omp parallel num_threads(2) { puts("para_b"); } puts("b ended"); } int main(){ a(); // Invokes OpenMP features (parent process) int p = fork(); if(!p){ b(); // ERROR: Uses OpenMP again, but in child process _exit(0); } wait(NULL); return 0; }运行时,该程序挂起,永远不会到达输出“b”的行 结束”。目前没有解决方法,因为 libgomp API 没有 指定可用于准备调用
fork()的函数。
【问题讨论】:
-
这是执行两次
puts("para_b");? -
很可能这与分叉克隆只是当前线程的事实有关,而 OpenMP 期望它的线程池在那里,准备好执行东西。在第一次并行循环调用时,它将启动线程池并设置一些它正在运行的标志,并且在
b中,它只会将工作移交给线程池 - 但是没有任何线程支持,因为它们不存在于新流程中。一般来说,“thread”和“fork”模型很难协调,通常你只需要选择一个。 -
这是已知的。请参阅
libogmp错误报告:gcc.gnu.org/bugzilla/show_bug.cgi?id=52303 cmets 中的注释:“POSIX 仅列出了一些您可以在 fork 之后调用的函数,然后再调用 _exit 或 exec*。#pragma omp parallel 绝对不是您可以在 fork 之后执行的操作来自多线程程序。”