如果不包含 pthread,为什么 GCC 的线程标准库实现会抛出异常?
Why does GCC's threading standard library implementation throw exceptions if you don't include pthread?
例如,当我编写使用 std::promise
的代码并且不在 GCC 中包含 PThread 库时,我会抛出异常而不是链接器错误。例如:
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
的情况下编译此代码,则会抛出以下异常:
terminate called after throwing an instance of 'std::system_error'
what(): Unknown error -1
Aborted (core dumped)
如果 std::promise
在内部使用 pthread
库,那么如果我不将 -pthread
命令行选项提供给 g++
,它应该会正确抛出链接错误。但它的编译没有任何错误,而 运行 我遇到了上述问题。
这是因为 libstdc++
使用了所谓的 weak references。
我们可以轻松追踪您的特定代码示例抛出异常的原因。 set_value()
调用 std::call_once
。该函数在其实现中具有 the line*:
int e = gthread_once(&once.M_once, &once_proxy);
其中 gthread_once
is:
static inline int gthread_once(gthread_once_t *once, void (*func)(void))
{
if (gthread_active_p())
return ...
else
return -1;
}
gthread_active_p
returnsfalse
,所以才会出现gthread_once
returns-1
,就是异常字符串中提到的[=47] =]
现在 take a look 在 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
,>hrw_pthread_key_create
将是一个空指针,如果找到 __pthread_key_create
,gthrw_pthread_key_create
将是它的别名。 __pthread_key_create
由 pthreads
库导出。
标准库源代码还有contains以下注释:
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 intercept pthread_create
with their own definitions to wrap pthreads
functionality for some purpose. In those cases, pthread_create
being defined might not necessarily mean that libpthread
is actually linked in.
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.
* 删除了一些下划线并扩展了宏以提高可读性。
例如,当我编写使用 std::promise
的代码并且不在 GCC 中包含 PThread 库时,我会抛出异常而不是链接器错误。例如:
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
的情况下编译此代码,则会抛出以下异常:
terminate called after throwing an instance of 'std::system_error'
what(): Unknown error -1
Aborted (core dumped)
如果 std::promise
在内部使用 pthread
库,那么如果我不将 -pthread
命令行选项提供给 g++
,它应该会正确抛出链接错误。但它的编译没有任何错误,而 运行 我遇到了上述问题。
这是因为 libstdc++
使用了所谓的 weak references。
我们可以轻松追踪您的特定代码示例抛出异常的原因。 set_value()
调用 std::call_once
。该函数在其实现中具有 the line*:
int e = gthread_once(&once.M_once, &once_proxy);
其中 gthread_once
is:
static inline int gthread_once(gthread_once_t *once, void (*func)(void))
{
if (gthread_active_p())
return ...
else
return -1;
}
gthread_active_p
returnsfalse
,所以才会出现gthread_once
returns-1
,就是异常字符串中提到的[=47] =]
现在 take a look 在 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
,>hrw_pthread_key_create
将是一个空指针,如果找到 __pthread_key_create
,gthrw_pthread_key_create
将是它的别名。 __pthread_key_create
由 pthreads
库导出。
标准库源代码还有contains以下注释:
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.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 aspthread_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 staticlibpthread.a
always links in wheneverpthread_create
is used, so there is no danger of a false negative result in any statically-linked, multi-threaded program.
* 删除了一些下划线并扩展了宏以提高可读性。