我认为这是 GOMP 中的一个已知问题,请参阅错误 42616 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42616 and 错误 52738 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52738.
这是关于如果您尝试在非主线程上使用 OpenMP 指令或函数,您的应用程序将会崩溃,并且可以追溯到gomp_thread()
功能 (see libgomp/libgomp.h https://android.googlesource.com/toolchain/gcc/+/master/gcc-4.6/libgomp/libgomp.h@第362行和第368行)返回NULL
对于您创建的线程:
#ifdef HAVE_TLS
extern __thread struct gomp_thread gomp_tls_data;
static inline struct gomp_thread *gomp_thread (void)
{
return &gomp_tls_data;
}
#else
extern pthread_key_t gomp_tls_key;
static inline struct gomp_thread *gomp_thread (void)
{
return pthread_getspecific (gomp_tls_key);
}
#endif
正如您所看到的,GOMP 根据线程本地存储 (TLS) 是否可用而使用不同的实现。
- 如果可用的话
HAVE_TLS
设置了flag,并使用一个全局变量来跟踪每个线程的状态,
- 否则,线程本地数据将通过该函数进行管理
pthread_setspecific
.
在 NDK 的早期版本中,线程本地存储(__thread
关键字)不受支持,所以HAVE_TLS
不会被定义,因此pthread_setspecific
将会被使用。
备注:我不确定是否__thread
NDK 的最新版本是否支持,但是here https://stackoverflow.com/questions/27191214/no-luck-compiling-thread-using-ndk-clang-3-4-3-5您可以阅读有关 Android TLS 的相同答案。
当 GOMP 创建工作线程时,它会在函数中设置线程特定数据gomp_thread_start()
(第 72 行):
#ifdef HAVE_TLS
thr = &gomp_tls_data;
#else
struct gomp_thread local_thr;
thr = &local_thr;
pthread_setspecific (gomp_tls_key, thr);
#endif
但是,当应用程序独立创建线程时,不会设置线程特定数据,因此gomp_thread()
函数返回NULL
。这会导致崩溃,但在支持 TLS 时这不是问题,因为使用的全局变量始终可用
我记得这个问题已经解决了android-ndk-r10d
,但它仅适用于后台进程(无 Java)。这意味着当您启用 OpenMP 并从 JNI(从 Java Android 中调用)创建本机线程时,您的应用程序将仍然崩溃。