这个答案build议-pthread
比-lpthread
更好,因为预定义的macros。
经验上, -pthread
只给我一个额外的macros: #define _REENTRANT 1
,它也强制libpthread.so.0
作为dynamic链接时间依赖。
当我使用-lpthread
编译时,只有在实际调用任何pthread
函数时才会添加该依赖项。
这对我来说最好,因为那样我就不必在构build脚本中以不同的方式处理multithreading程序。
所以我的问题是,还有什么是-pthread
vs -lpthread
,是否有可能使用use -pthread
而不强制所说的dynamic链接时间依赖?
示范:
$ echo 'int main(){ return 0; }' | c gcc -include pthread.h -xc - -lpthread && ldd a.out | grep pthread $ echo 'int main(){ return pthread_self(); }' | c gcc -include pthread.h -xc - -lpthread && ldd a.out | grep pthread libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x0000003000c00000) $ echo 'int main(){ return 0; }' | c gcc -include pthread.h -xc - -pthread && ldd a.out | grep pthread libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x0000003000c00000)
你应该使用GCC的特殊选项-pthread
而不是-lpthread
的想法已经过时了大概十五年(就glibc而言)。 在现代的glibc中,线程切换是完全动态的,取决于pthreads库是否被链接。 glibc头文件中的内容根据是否定义了_REENTRANT
来改变其行为。
作为动态切换的例子,考虑FILE *
流。 流上的某些操作是锁定的,就像putc
。 无论您是在编译单线程程序,它都会调用相同的putc
函数。 它不会被预处理器重新路由到“pthread-aware” putc
。 会发生什么事情是,无用存根函数被用来通过锁定和解锁的动作。 线程库链接时,这些函数被覆盖到真正的函数。
我只是通过glibc安装的包含文件树进行粗略的grep
。 在features.h
, _REENTRANT
导致__USE_REENTRANT
被定义。 反过来,正好一件事情似乎取决于__USE_REENTRANT
是否存在,但具有并行条件,这也使得它。 也就是说,在<unistd.h>
有这个:
#if defined __USE_REENTRANT || defined __USE_POSIX199506 /* Return at most NAME_LEN characters of the login name of the user in NAME. If it cannot be determined or some other error occurred, return the error code. Otherwise return 0. This function is a possible cancellation point and therefore not marked with __THROW. */ extern int getlogin_r (char *__name, size_t __name_len) __nonnull ((1)); #endif
这看起来可疑,已经过时; 我无法在glibc git repo的master分支中找到它。
而且,哦,看, 就在几天前 (十二月六日)就这个话题提出了一个承诺:
https://sourceware.org/git/?p=glibc.git;a=commit;h=c03073774f915fe7841c2b551fe304544143470f
Make _REENTRANT and _THREAD_SAFE aliases for _POSIX_C_SOURCE=199506L. For many years, the only effect of these macros has been to make unistd.h declare getlogin_r. _POSIX_C_SOURCE >= 199506L also causes this function to be declared. However, people who don't carefully read all the headers might be confused into thinking they need to define _REENTRANT for any threaded code (as was indeed the case a long time ago).
在这些变化中:
--- a/posix/unistd.h +++ b/posix/unistd.h @@ -849,7 +849,7 @@ extern int tcsetpgrp (int __fd, __pid_t __pgrp_id) __THROW; This function is a possible cancellation point and therefore not marked with __THROW. */ extern char *getlogin (void); -#if defined __USE_REENTRANT || defined __USE_POSIX199506 +#ifdef __USE_POSIX199506 /* Return at most NAME_LEN characters of the login name of the user in NAME. If it cannot be determined or some other error occurred, return the error code. Otherwise return 0.
看到? 🙂
另一个答案解释说, 当C库是GNU C库时 , -pthread
(在编译和链接时)在功能上等价于-lpthread
(仅在链接时)。 但这不是世界上唯一的C库。
我不知道当前任何符合POSIX标准的操作系统是否需要在链接时使用超过-lpthread
的线程,但是如果在编译和链接时都使用-pthread
,那么至少可以使生活更轻松对于那些试图保持老铁运行的人来说。
话虽如此,如果您在不需要使用线程的程序中不使用-pthread
(或-lpthread
),那么旧的铁也将会更快乐。 “通用项目构建”不是一个好主意。
当不需要共享库时,共享库的问题最好通过随时(用GNU兼容的连接器)来解决。 这只是默认情况下为了向后兼容的缘故。