本文介绍了如果不包含pthread,为什么GCC的线程标准库实现会引发异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我编写使用例如 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 *)&gthrw_pthread_key_create;
  return gthread_active_ptr != 0;
}

gthrw_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, &gthrw_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:

对于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的线程标准库实现会引发异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 16:10