如何创build一个仅在pthread链接时才使用互斥体的库?

我正在Linux上创build一个C库,它有几个function,它们共同操作一些全局数据。 为了使这些函数成为线程安全的,他们必须在代码中的适当位置使用互斥锁。

在Linux中,为了在应用程序中使用pthread,需要在适当的库中链接-lpthread 。 在编译我的库的情况下,如果它的用户决定在他们的应用程序中使用pthreads,并且他们不这样做,我想让它工作。

在开发人员在应用程序中不使用线程的情况下,它们不会与pthreads链接。 因此,我希望我编译的库不要求它,而且,在单线程应用程序中使用互斥体使用不必要的开销(更不用说是愚蠢的)。

是否有某种方式来编写代码(如果有必要,使用GCC扩展)只有某些符号被链接时,某个代码块才会运行? 我知道我可以使用dlopen()和朋友,但是这本身就需要一些我想要避免的东西。 我想我所要找的东西必须存在,因为几个标准函数在同一条船上,并且需要互斥体是线程安全的(而且是互斥的),但是即使不与pthread链接,也能工作。

在这一点上,我注意到66&67行上的FreeBSD的popen()函数使用了非可移植的检查 – isthreaded ,以确定是否使用线程,以及是否使用互斥锁。 我怀疑这样的东西是否以任何方式标准化。 但是更重要的是,如果符号不被识别,那么这样的代码就不能编译和链接,而在Linux中,如果pthread没有链接,互斥符号将不会存在。

总结一下:在Linux上,如何创build一个库,它知道什么时候使用线程,如果是,在适当的情况下使用互斥锁,并且不需要链接到pthread,除非应用程序开发人员特别想在某处使用线程。

Solutions Collecting From Web of "如何创build一个仅在pthread链接时才使用互斥体的库?"

经过一番测试,似乎Linux已经做了我想要的自动! 如果你使用线程,你只需要链接到pthreads,而不是如果你只是想要pthread互斥体的支持。

在这个测试案例中:

 #include <stdio.h> #include <errno.h> #include <pthread.h> int main() { pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; if (!(errno = pthread_mutex_lock(&mutex))) { puts("Mutex locked!"); } else { perror("Could not lock mutex"); } if (!(errno = pthread_mutex_lock(&mutex))) { puts("Mutex locked!"); } else { perror("Could not lock mutex"); } return 0; } 

当编译这没有pthreads链接,我看到“互斥锁! 两次。 这表明pthread_mutex_lock()本质上是一个非操作符。 但是与pthreads链接,运行此应用程序将停止后第一次“互斥锁! 被打印。

因此,我可以在适当的情况下在我的库中使用互斥锁,并且不需要使用pthread来使用,也不需要(不必要的)开销。

通常的解决方案是:

  1. 使用#define开关在构建时控制是否调用pthreads函数,并让你的构建过程创建你的库的两个版本:一个是pthread-aware,一个是不知名的。 依靠你的图书馆的用户链接正确的。

  2. 不要直接调用pthreads函数,而是调用用户提供的lockunlock回调(如果需要,也可以调用线程本地存储)。 库用户负责分配和调用适当的锁定机制,这也允许他们使用非线程库线程库。

  3. 什么都不要做,只是记录用户代码应该确保你的库函数不是从多个线程同时输入的。

glibc再次做了一些不同的事情 – 它使用带有惰性绑定符号的技巧,只有在链接到二进制文件中时才调用pthreads函数。 这不是可移植的,因为它依赖于pibread的glibc实现的具体细节。 查看__libc_maybe_call()的定义 :

 #ifdef __PIC__ # define __libc_maybe_call(FUNC, ARGS, ELSE) \ (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \ _fn != NULL ? (*_fn) ARGS : ELSE; })) #else # define __libc_maybe_call(FUNC, ARGS, ELSE) \ (FUNC != NULL ? FUNC ARGS : ELSE) #endif