要在多线程应用程序中使用 errno,此参考http://www.cplusplus.com/reference/cerrno/errno/表明它应该在每个线程中本地实现。这意味着什么?
3 回答
errno
应该是thread-local
。在这个变量的每个thread
值可以是不同的。
它应该在每个线程中本地实现
实现errno
为thread_local
变量不是您的职责。它适用于编译器开发人员。
errno 是用于错误指示的预处理器宏。 它扩展为 int 类型的线程局部可修改左值。 (C++11 起)
简单来说,在 C++11 编译器中,这段代码永远不应该断言
#include <iostream>
#include <cerrno>
#include <thread>
#include <cassert>
int g_errno = 0;
void thread_function()
{
errno = E2BIG;
g_errno = errno;
}
int main()
{
errno = EINVAL;
std::thread thread(thread_function);
thread.join();
assert(errno != g_errno && "not multithreaded");
}
从历史上看,errno
它是一个通用类型变量int
——即每个模块都有自己的定义,链接器负责合并它们。所以程序简单地在int errno;
全球范围内陈述并有一个工作定义。
这在多线程环境中会失效,因为只有一个变量。因此,errno.h
现在需要定义一个lvalue int
的东西,并且程序不应该定义自己的errno
.
例如,GNU C 库定义了类似于
#define errno (*(__errno_location()))
where__errno_location()
是一个计算线程本地地址的内联函数errno
。
所有这些都与应用程序无关,除非定义自己的errno
.
这意味着每个线程都应该有自己的errno
变量实例
该实现可以通过使用类似的东西轻松实现这一点:
int __thread errno;
__thread
作为一个 gcc 扩展,确保变量是线程本地的(因此一个线程不能覆盖变量的另一个线程实例)
作为 errno 的用户,您无需担心这一点。您甚至不必担心 errno 可能已被另一个线程抢先更改。