为什么我在使用 OpenMP 的共享库中的函数在通过 swig 从子进程调用时挂起?

Why does my function in a shared library which uses OpenMP hang when called from a subprocess via swig?

我正在尝试包装一个最小的 C 库,它由一个文件 "locks.h" 组成,其中包含

#ifndef LOCKS_H
#define LOCKS_H
void f(void);
#endif

和"locks.c"包含

#include <stdio.h>

void f(void) {
#pragma omp parallel
  {
    fprintf(stderr, "Hello World!\n");
  }
  return;
}

with swig,使用包含

的 swig 输入文件 "locks.i"
%module locks

%{
#define SWIG_FILE_WITH_INIT
#include "locks.h"
%}

void f(void);

然后我使用

创建并构建包装器
swig -python locks.i
gcc -fPIC -shared -I/usr/include/python3.6/ -fopenmp locks.c locks_wrap.c -g -o _locks.so

和像

这样的快速测试
python3 -c "import locks; locks.f()"

似乎按预期工作。

但是,当我调用函数 f 两次时,一次来自 python 主进程,一次来自这样的子进程:

from multiprocessing import Process

import locks

locks.f()

print('Launching Process')
p = Process(target=locks.f)
p.start()
p.join()
print(p.exitcode)

代码挂在子进程的调用中,只打印

Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Launching Process
Hello World!

在 Python 3.6 和

Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Launching Process

在 Python 3.8 中,Intel CPU 具有 4 个内核和 8 个超线程。

如果我只从子进程中调用函数,而不是在两个进程中调用,那么子进程中的调用也会按预期成功。

目标系统是 64 位 Linux(本例中为 Ubuntu 18.04)。

我该如何解决这个问题?

正如Zulan in a comment, the core issue appears to be that 所指出的那样。

幸运的是,Python 多处理允许您使用 set_start_method() 函数请求它从头开始生成全新的解释器进程,而不是分叉。

因此,通过将 python 脚本调整为

import multiprocessing as mp

import locks

if __name__ == '__main__':
    mp.set_start_method('spawn')

    locks.f()

    print('Launching Process')
    p = mp.Process(target=locks.f)
    p.start()
    p.join()
    print(p.exitcode)

问题已解决。