如果不包含pthread,为什么GCC的线程标准库实现会引发异常? [英] Why does GCC's threading standard library implementation throw exceptions if you don't include pthread?
问题描述
当我编写使用例如 std :: promise
的代码,并且在GCC中不包含PThread库时,会抛出异常,而不是链接器错误。例如:
When I write code that uses, for example, std::promise
, and I don't include the PThread library in GCC, I get an exception thrown rather than a linker error. For example:
void product(std::promise<int> intPromise, int a, int b)
{
intPromise.set_value(a * b);
}
int main()
{
int a = 20;
int b = 10;
std::promise<int> prodPromise;
std::future<int> prodResult = prodPromise.get_future();
product(std::move(prodPromise), a, b);
std::cout << "20*10= " << prodResult.get() << std::endl;
}
如果我在不使用 -pthread的情况下编译此代码
,将引发以下异常:
If I compile this code without -pthread
, the following exception is thrown:
terminate called after throwing an instance of 'std::system_error'
what(): Unknown error -1
Aborted (core dumped)
如果 std :: promise
在内部使用 pthread
库,如果我不给它,它应该抛出正确的链接错误 -pthread
命令行选项,用于 g ++
。但是它编译时没有任何错误,并且在运行时遇到了上述问题。
If std::promise
using the pthread
library internally, then it should throw linkage error right if I don't give the -pthread
commandline option to g++
. But it's compiling without any errors and while running I am getting the above issue.
推荐答案
原因是 libstdc ++
使用所谓的弱引用。
我们可以轻松地跟踪为什么您的特定代码示例引发异常。 set_value()
调用 std :: call_once
。该函数在其实现中具有该行 * :
We can easily trace why your particular code example throws an exception. set_value()
calls std::call_once
. That function in its implementation has the line*:
int e = gthread_once(&once.M_once, &once_proxy);
其中 gthread_once
是:
static inline int gthread_once(gthread_once_t *once, void (*func)(void))
{
if (gthread_active_p())
return ...
else
return -1;
}
gthread_active_p
返回 false
,这就是为什么 gthread_once
返回 -1
的原因
gthread_active_p
returns false
, that's why gthread_once
returns -1
, which is mentioned in the exception string.
现在让我们看看在 gthread_active_p
:
static __typeof(pthread_key_create) gthrw_pthread_key_create
__attribute__ ((weakref("__pthread_key_create")));
static inline int gthread_active_p(void)
{
static void *const gthread_active_ptr = (void *)>hrw_pthread_key_create;
return gthread_active_ptr != 0;
}
gthrw_pthread_key_create
是对 __ pthread_key_create
的引用不足。如果链接器未找到符号 __ pthread_key_create
,则& gthrw_pthread_key_create
将为空指针,如果<$ c找到$ c> __ pthread_key_create , gthrw_pthread_key_create
将为其别名。 __ pthread_key_create
由 pthreads
库导出。
gthrw_pthread_key_create
is a weak reference to __pthread_key_create
. If there is no symbol __pthread_key_create
found by the linker, >hrw_pthread_key_create
will be a null pointer, if __pthread_key_create
is found, gthrw_pthread_key_create
will be an alias for it. __pthread_key_create
is exported by the pthreads
library.
标准库源代码也包含以下注释:
The standard library source code also contains the following comment:
要使程序成为多线程程序,它肯定必须使用的唯一内容是
pthread_create
。但是,可能还有其他一些库使用自己的定义拦截pthread_create
来包装pthreads
功能。在这些情况下,定义pthread_create
不一定意味着实际上已链接libpthread
。
For a program to be multi-threaded the only thing that it certainly must be using is
pthread_create
. However, there may be other libraries that interceptpthread_create
with their own definitions to wrappthreads
functionality for some purpose. In those cases,pthread_create
being defined might not necessarily mean thatlibpthread
is actually linked in.
对于GNU C库,我们可以使用一个已知的内部名称。它在ABI中始终可用,但是没有其他库可以定义它。这是理想的,因为任何公共 pthread
函数都可能会被拦截,就像 pthread_create可能是
一样。 __ pthread_key_create
是一个内部实现符号,但它是公共导出的ABI的一部分。此外,在使用 pthread_create
时,静态 libpthread.a
总是会链接到这些符号中,因此没有在任何静态链接的多线程程序中都有错误的否定结果的危险。
For the GNU C library, we can use a known internal name. This is always available in the ABI, but no other library would define it. That is ideal, since any public pthread
function might be intercepted just as pthread_create might be
. __pthread_key_create
is an "internal" implementation symbol, but it is part of the public exported ABI. Also, it's among the symbols that the static libpthread.a
always links in whenever pthread_create
is used, so there is no danger of a false negative result in any statically-linked, multi-threaded program.
* 删除了一些下划线,并扩展了宏以提高可读性。
* Some underscores are removed and macros are expanded to improve readability.
这篇关于如果不包含pthread,为什么GCC的线程标准库实现会引发异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!