问题描述
这个建议 -pthread 优于 -lpthread 因为预定义的宏。
经验上讲, -pthread 只给我一个额外的宏: #define _REENTRANT 1
,它也会强制 libpthread.so.0 作为动态linktime依赖。
当我用 -lpthread ,只有在我实际调用任何 pthread 函数时才会添加依赖项。
对我来说,因为那样我就不必在构建脚本中对待多线程程序了。
> -pthread vs -lpthread 并且可以在不强制的情况下使用use -pthread 说动态linktime依赖?演示:
$ 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)
您应该使用GCC的特殊选项 -pthread 而不是 -lpthread 的想法已过时大概有十五年的时间(就glibc而言,就是这样)。在现代的glibc中,线程切换是完全动态的,取决于pthreads库是否被链接。根据是否定义了 _REENTRANT ,glibc头文件中的内容不会改变其行为。
,请考虑 FILE * 流。流上的某些操作是锁定的,如 putc 。无论您是在编译单线程程序,它都会调用相同的 putc 函数;它不会被预处理器重新路由到pthread-aware putc 。会发生什么事情是,无用存根函数被用来通过锁定和解锁的动作。当线程库被链接时,这些函数被覆盖为真正的函数。<通过glibc安装的包含文件树,我刚刚做了一个粗略的 grep 。在 features.h中定义 __ US $ _REENTRANT 。反过来,正好有一件事似乎取决于是否存在 __ USE_REENTRANT ,但具有并行条件,这也使得它成为可能。也就是说,在< unistd.h> 中有这样的:
#if定义__USE_REENTRANT ||定义__USE_POSIX199506
/ *返回NAME中用户登录名的至多NAME_LEN个字符。
如果无法确定或发生其他错误,请返回错误
代码。否则返回0.
这个函数是一个可能的取消点,因此不是用__THROW标记的
。 * /
extern int getlogin_r(char * __ name,size_t __name_len)__nonnull((1));
#endif
这看起来很可疑并且已经过时;我无法在glibc git repo的master分支中找到它。
另外,仅仅是在几天前(12月6日)对此主题进行了提交:
为_POSIX_C_SOURCE = 199506L制作_REENTRANT和_THREAD_SAFE别名。
多年来,这些宏的唯一影响是使
unistd.h声明了getlogin_r。 _POSIX_C_SOURCE> = 199506L也会导致
这个函数被声明。然而,不小心
读取所有头文件的人可能会觉得困惑,因为他们认为他们需要
为任何线程代码定义_REENTRANT(就像前面的
长时间的情况一样)。
其中包括:
$ b $
--- a / posix / unistd.h
+++ b / posix / unistd.h
@@ -849,7 +849,7 @@ extern int tcsetpgrp (int __fd,__pid_t __pgrp_id)__THROW;
这个函数是一个可能的取消点,因此不是用__THROW标记的
。 * /
extern char * getlogin(void);
- #如果已定义__USE_REENTRANT ||定义__USE_POSIX199506
+#ifdef __USE_POSIX199506
/ *在NAME中最多返回用户登录名的NAME_LEN个字符。
如果无法确定或发生其他错误,请返回错误
代码。否则返回0.
请参见:)
This answer suggest -pthread is preferable to -lpthread because predefined macros.
Empirically, -pthread gives me only one extra macro: #define _REENTRANT 1and it also appears to force libpthread.so.0 as a dynamic linktime dependency.
When I compile with -lpthread, that dependency is only added if I actually call any of the pthread functions.
This is preferably to me, because then I wouldn't have to treat multithreaded programs differently in my build scripts.
So my question is, what else is there to -pthread vs -lpthread and is it possible to use use -pthread without forcing said dynamic linktime dependency?
Demonstration:
$ 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)
The idea that you should use GCC's special option -pthread instead of -lpthread is outdated by probably some decade and a half (with respect to glibc, that is). In modern glibc, the switch to threading is entirely dynamic, based on whether the pthreads library is linked or not. Nothing in the glibc headers changes its behavior based on whether _REENTRANT is defined.
As an example of the dynamic switching, consider FILE * streams. Certain operations on streams are locking, like putc. Whether you're compiling a single-threaded program or not, it calls the same putc function; it is not re-routed by the preprocessor to a "pthread-aware" putc. What happens is that do-nothing stub functions are used to go through the motions of locking and unlocking. These functions get overridden to real ones when the threading library is linked in.
I just did a cursory grep through the include file tree of a glibc installation. In features.h, _REENTRANT causes __USE_REENTRANT to be defined. In turn, exactly one thing seems to depend on whether __USE_REENTRANT is present, but has a parallel condition which also enables it. Namely, in <unistd.h> there is this:
#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
This looks dubious and is obsolete; I can't find it in the master branch of the glibc git repo.
And, oh look, just mere days ago (December 6) a commit was made on this topic:
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).
Among the changes:
--- 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.
See? :)
这篇关于-pthread,-lpthread和最小的动态链接时间依赖性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!