-pthread,-lpthread和最小动态链接时间依赖性

PSk*_*cik 4 c linux gcc glibc pthreads

这个答案建议-pthread-lpthread预定义的宏更可取.

根据经验,-pthread只给我一个额外的宏:#define _REENTRANT 1 它似乎也强制libpthread.so.0作为动态链接时间依赖.

当我编译时-lpthread,只有在我实际调用任何pthread函数时才会添加该依赖项.

这对我来说最好,因为那时我不必在构建脚本中以不同方式处理多线程程序.

所以我的问题是,-pthreadvs 还有什么用的-lpthread,是否可以在-pthread不强制表示动态链接时依赖的情况下使用?

示范:

$ echo 'int main(){ return 0; }' | c gcc -include pthread.h -x c - -lpthread && ldd a.out | grep pthread
$ echo 'int main(){  return pthread_self(); }' | c gcc -include pthread.h -x c - -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 -x c - -pthread && ldd a.out | grep pthread
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x0000003000c00000) 
Run Code Online (Sandbox Code Playgroud)

Kaz*_*Kaz 9

您应该使用GCC的特殊选项-pthread而不是-lpthread过时的想法已经过时了大约十五年(相对于glibc而言).在现代的glibc中,根据pthreads库是否链接,切换到线程是完全动态的.glibc头中的任何内容都_REENTRANT不会根据是否定义来更改其行为.

作为动态切换的示例,考虑FILE *流.流上的某些操作是锁定的,比如putc.无论您是否编译单线程程序,它都会调用相同的putc函数; 它不会被预处理器重新路由到"pthread-aware" putc.发生的事情是,无用的存根函数用于完成锁定和解锁的动作.当链接线程库时,这些函数会被覆盖为真实的函数.



我刚刚grep通过glibc安装的include文件树做了一个粗略的.在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
Run Code Online (Sandbox Code Playgroud)

这看起来很可疑,已经过时了; 我无法在glibc git repo的master分支中找到它.

哦,看,就在几天前(12月6日),就这一主题做出了承诺:

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).
Run Code Online (Sandbox Code Playgroud)

其中包括:

--- 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.
Run Code Online (Sandbox Code Playgroud)

看到?:)

  • "你应该使用GCC的特殊选项-pthread而不是-lpthread的想法已经过时了大约十五年(相对于glibc而言)." - 这是正确的,但***适用于glibc.如果你为其他平台构建,你很容易通过*不*使用`-pthread`来解决问题,因此最好使用`-pthread`而不是`-lpthread`,因为前者总是*正确,并且后者不一定. (2认同)

zwo*_*wol 5

另一个答案解释说-pthread(在编译和链接时)在功能上等同于-lpthread(仅在链接时)当 C 库是 GNU C 库时。但这并不是世界上唯一的 C 库。

我不知道当前一代 POSIX 兼容的操作系统是否需要-lpthread线程应用程序的链接时以外的任何东西,但是如果您-pthread在编译和链接时使用,您至少会让人们的生活更轻松保持旧铁运转。

话虽如此,老铁也会更快乐,如果你在不需要使用线程的程序上使用-pthread(或-lpthread)。“通用项目构建”不是一个好主意。

共享库在不需要时被引入的问题最好通过-Wl,--as-needed(使用 GNU 兼容的链接器)来解决。出于向后兼容性的考虑,这只是默认情况下不启用。