原子和 errno:使用 C++11 原子读取受保护的 errno 值是否合理?
Atomics and `errno`: is it reasonable to use C++11 atomics to read a protected errno value?
处理 errno 是在多线程环境中使用 POSIX API 的难题之一。像下面这样使用 std::atomic
的锁是否合理?
class FastLock{
std::atomic_int value;
public:
FastLock()
: value{0}{}
void unlock()
{
value.store(0,std::memory_order_release);
}
bool try_lock()
{
int r = value.exchange(1,std::memory_order_acquire);
return !r;
}
};
上下文类似于:
template<typename function, typename ...args>
auto shield(function _fn){
static FastLock* lk = new FastLock{};
return [=](args... _v){
while(lk->try_lock());
auto ret = std::forward(_fn, _v...);
auto errval = errno;
lk->unlock();
return std::make_pair(ret,errval);
};
}
这会导致任何类型的未定义行为或实现定义的行为吗?
虽然 1988 年的旧 POSIX 标准曾经要求 errno
是全局对象,但在以后的修订版中不再如此。至少 POSIX.1-2001 要求 errno
是线程本地的。我怀疑 POSIX.1c-1995 已经要求它指定 POSIX 线程,但我无权访问该文档,所以我无法验证。
我不认为支持 C++11 的 POSIX 系统也不会支持 POSIX 2001,因此,使用 C++11 原子似乎不太可能必要的。
也就是说,虽然 C 标准不要求 errno
是一个全局对象(至少 C99 不需要),但它也不保证 errno
的线程局部性。因此,在非 POSIX 系统或不提供线程局部性的旧 POSIX 系统上可能需要锁定 errno
。如果出于某种原因该平台确实支持 C++11,那么 C++11 原子可能是实现锁的理想选择——也可能不是。至少理论上是这样。
请注意,为了保证线程安全,您必须确保对可能设置 errno
的函数的所有调用都必须使用锁。如果您使用任何可能使用此类标准函数的库,您也必须锁定对此类函数的调用。
处理 errno 是在多线程环境中使用 POSIX API 的难题之一。像下面这样使用 std::atomic
的锁是否合理?
class FastLock{
std::atomic_int value;
public:
FastLock()
: value{0}{}
void unlock()
{
value.store(0,std::memory_order_release);
}
bool try_lock()
{
int r = value.exchange(1,std::memory_order_acquire);
return !r;
}
};
上下文类似于:
template<typename function, typename ...args>
auto shield(function _fn){
static FastLock* lk = new FastLock{};
return [=](args... _v){
while(lk->try_lock());
auto ret = std::forward(_fn, _v...);
auto errval = errno;
lk->unlock();
return std::make_pair(ret,errval);
};
}
这会导致任何类型的未定义行为或实现定义的行为吗?
虽然 1988 年的旧 POSIX 标准曾经要求 errno
是全局对象,但在以后的修订版中不再如此。至少 POSIX.1-2001 要求 errno
是线程本地的。我怀疑 POSIX.1c-1995 已经要求它指定 POSIX 线程,但我无权访问该文档,所以我无法验证。
我不认为支持 C++11 的 POSIX 系统也不会支持 POSIX 2001,因此,使用 C++11 原子似乎不太可能必要的。
也就是说,虽然 C 标准不要求 errno
是一个全局对象(至少 C99 不需要),但它也不保证 errno
的线程局部性。因此,在非 POSIX 系统或不提供线程局部性的旧 POSIX 系统上可能需要锁定 errno
。如果出于某种原因该平台确实支持 C++11,那么 C++11 原子可能是实现锁的理想选择——也可能不是。至少理论上是这样。
请注意,为了保证线程安全,您必须确保对可能设置 errno
的函数的所有调用都必须使用锁。如果您使用任何可能使用此类标准函数的库,您也必须锁定对此类函数的调用。