如果不包含 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_preturnsfalse,所以才会出现gthread_oncereturns-1,就是异常字符串中提到的[=47] =]

现在 take a lookgthread_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 *)&gthrw_pthread_key_create;
  return gthread_active_ptr != 0;
}

gthrw_pthread_key_create__pthread_key_create。如果链接器没有找到符号 __pthread_key_create&gthrw_pthread_key_create 将是一个空指针,如果找到 __pthread_key_creategthrw_pthread_key_create 将是它的别名。 __pthread_key_createpthreads 库导出。

标准库源代码还有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.


* 删除了一些下划线并扩展了宏以提高可读性。