【发布时间】:2013-07-12 09:49:46
【问题描述】:
要在多线程应用程序中使用 errno,此引用 http://www.cplusplus.com/reference/cerrno/errno/ 表明它应该在每个线程中本地实现。这是什么意思?
【问题讨论】:
要在多线程应用程序中使用 errno,此引用 http://www.cplusplus.com/reference/cerrno/errno/ 表明它应该在每个线程中本地实现。这是什么意思?
【问题讨论】:
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 类型的common 变量——即每个模块都有自己的定义,链接器负责合并它们。所以程序在全球范围内简单地声明int errno;,并有一个工作定义。
这在多线程环境中会失效,因为只有一个变量。因此,errno.h 现在需要定义一个左值 int,程序不应该定义自己的errno。
例如,GNU C 库定义了类似于
#define errno (*(__errno_location()))
其中__errno_location() 是一个内联函数,用于计算线程本地errno 的地址。
所有这些都与应用程序无关,除了定义自己的errno 是错误的。
【讨论】:
extern int errno; 也有效,因为它也可以用来指代一个通用定义。但是,使用 int errno = 0; 初始化无法链接。
这意味着每个线程都应该有自己的errno变量实例
实现可以通过使用类似的东西轻松实现:
int __thread errno;
__thread 是一个 gcc 扩展,可确保变量是线程本地的(因此一个线程不能覆盖该变量的另一个线程实例)
作为 errno 的用户,您无需担心这一点。您甚至不必担心 errno 可能已被另一个线程抢先更改。
【讨论】: