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

时间:2016-12-21 16:05:51

标签: c linux gcc pthreads glibc

answer建议-pthread优于-lpthread因为预定义的宏。

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

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

这对我来说最好,因为那样我就不必在构建脚本中对待多线程程序。

所以我的问题是,-pthread vs -lpthread还有什么其他内容,是否可以使用use -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) 

2 个答案:

答案 0 :(得分:8)

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

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

我刚刚通过glibc安装的include文件树做了一个粗略的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的主分支中找到它。

而且,哦,看,仅仅几天前(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).

其中包括:

--- 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.

看?:)

答案 1 :(得分:3)

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

我不知道任何当前生成的符合POSIX标准的操作系统是否在链接时需要超过-lpthread的线程应用程序,但如果使用{{1在编译和链接时,你至少会让那些试图保持旧铁运行的人更轻松。

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

-lpthread(与GNU兼容的链接器)可以最好地解决共享库在不需要时被拉入的问题。默认情况下,为了向后兼容,这不会打开。