LoginSignup
2
5

More than 5 years have passed since last update.

MacOSXでpthreadとOpenMPを共存させる

Last updated at Posted at 2016-04-13

問題

OpenMPを使って並列化されている処理をpthreadで作ったthreadから呼ぶことを考える。例えば、以下のようなコード。

main関数の中でpthreadを4つ作り、それぞれのthreadでループをOpenMPで並列化した処理を実行したい。

test_thread_omp.cpp
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <omp.h>

#define NTHREADS 4

void *myFun(void *x)
{
  int tid;
  tid = *((int *) x);
  printf("Hi from thread %d!\n", tid);
  #pragma omp parallel
  {
    int n = omp_get_num_threads();
    #pragma omp master
    printf("num threads: %d\n", n);
    #pragma omp for
    for( int i=0; i < n; i++) {
      int t = omp_get_thread_num();
      printf("I'm thread %d-%d!\n", tid, t );
    }
  }
  return NULL;
}

int main(int argc, char *argv[])
{
  pthread_t threads[NTHREADS];
  int thread_args[NTHREADS];
  int rc, i;

  /* spawn the threads */
  for (i=0; i<NTHREADS; ++i)
    {
      thread_args[i] = i;
      printf("spawning thread %d\n", i);
      rc = pthread_create(&threads[i], NULL, myFun, (void *) &thread_args[i]);
    }

  /* wait for threads to finish */
  for (i=0; i<NTHREADS; ++i) {
    rc = pthread_join(threads[i], NULL);
  }

  return 0;
}

このようなpthreadとOpenMPの混在はWindowsやLinuxでは問題なく動くようであるが、Macの場合にはmain threadから呼ばないとSEGVが発生するという情報を発見した(http://stackoverflow.com/a/8446942)。

これを実際に自分で検証した。
OSXのデフォルトのコンパイラclangではそもそもOpenMPに非対応のためhomebrewでgccを入れる。
gccを入れる方法は Homebrew で gcc4.7 を入れる を参照していただきたい。

実験結果

gcc-4.9で実験した場合、必ずセグメンテーションフォールトが発生する。

spawning thread 0
spawning thread 1
Hi from thread 0!
spawning thread 2
Hi from thread 1!
spawning thread 3
zsh: segmentation fault  ./a.out

デバッガでバックトレースをとると

$ lldb ./a.out
(lldb) target create "./a.out"
Current executable set to './a.out' (x86_64).
(lldb) run
Process 99724 launched: './a.out' (x86_64)
spawning thread 0
spawning thread 1
Hi from thread 0!
spawning thread 2
Process 99724 stopped
* thread #2: tid = 0x24c7ada, 0x00000001001c164b libgomp.1.dylib`gomp_resolve_num_threads + 43, stop reason = EXC_BAD_ACCESS (code=1, address=0x50)
    frame #0: 0x00000001001c164b libgomp.1.dylib`gomp_resolve_num_threads + 43
libgomp.1.dylib`gomp_resolve_num_threads:
->  0x1001c164b <+43>: movq   0x50(%rax), %rdx
    0x1001c164f <+47>: leaq   0xebca(%rip), %rax        ; gomp_global_icv
    0x1001c1656 <+54>: leaq   0x70(%rdx), %rbx
    0x1001c165a <+58>: testq  %rdx, %rdx

というエラーが起きて、どうやらOpenMPがスレッド数を取得しようとしたところで変なアドレスにアクセスしている模様。

一方、gcc-5で実験するとちゃんと動いてくれた。

spawning thread 0
spawning thread 1
Hi from thread 0!
spawning thread 2
Hi from thread 1!
spawning thread 3
Hi from thread 2!
Hi from thread 3!
I'm thread 2-2!
I'm thread 2-1!
num threads: 4
I'm thread 2-3!
num threads: 4
I'm thread 0-1!
I'm thread 0-2!
I'm thread 0-3!
I'm thread 2-0!
I'm thread 1-1!
I'm thread 1-2!
num threads: 4
I'm thread 1-3!
I'm thread 3-1!
I'm thread 3-2!
num threads: 4
I'm thread 0-0!
I'm thread 3-3!
I'm thread 1-0!
I'm thread 3-0!

結論

pthreadとOpenMPを混在させたい時はhomebrewでgcc5をインストールする

参考

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5