c++ - 如何以线程安全的方式初始化 C++ 全局互斥锁
问题描述
尝试使用函数静态互斥锁来使代码线程安全。问题不在于所有编译器都以线程安全的方式初始化函数静态变量。
void Initialize()
{
static Mutex L; // can't be initialized at compile time because constructor calls CreateMutex()
L.Lock()
// call thread unsafe code
L.Unlock()
}
以下是已经考虑的解决方案:
在全局范围内声明 Mutex,以便在 main() 之前进行初始化。不幸的是,当有一个全局变量的构造函数调用 Initialize() 时,这不起作用,因为在 C++ 中,不能保证全局变量的初始化顺序
使用原子操作
void Initialize()
{
static volatile uint16_t lock=0; // trivial initialization can happen @ compile time
while (AtomicExchange(lock,(uint16_t)1)!=0); // swap lock with 1 and return previous value
// call thread unsafe code
lock=0;
}
这可行,但有忙等待的缺点
使用 pthread 的编译时初始化程序
pthread_mutex_t 锁定 = PTHREAD_MUTEX_INITIALIZER;
不幸的是,这是针对 Windows 的,我们试图避免使用 pthread
欣赏可移植的解决方案。我知道在 C++ 2011 中,函数静态初始化是线程安全的,但我们避免使用 C++ 2011,因为某些嵌入式平台可能不可靠的 C++ 2011 支持。
解决方案
IMO 解决您的问题的方法是使用漂亮的反制成语。这个成语在这里有很好的描述:https ://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter 。
使用这个习惯用法std::cout
, std::cerr
,std::clog
流被初始化。唯一的要求是您需要正确计算创建类型的对齐方式。使用该对齐方式,您需要创建一个全局缓冲区。使用该缓冲区,可以创建具有放置新运算符的所需类型的实例。Boost 和 Modern C++ (>= C++11) 有(std|boost)::aligned_storage
模板类来为你创建一个正确对齐的缓冲区。请参阅:
- https://en.cppreference.com/w/cpp/types/aligned_storage
- https://www.boost.org/doc/libs/1_69_0/libs/type_traits/doc/html/boost_typetraits/reference/aligned_storage.html
现代版本的 C++ 具有alignof
运算符,可用于计算特定类型的对齐方式。在 boost 中,您需要使用类型特征alignment_of
:https ://www.boost.org/doc/libs/1_69_0/libs/type_traits/doc/html/boost_typetraits/reference/alignment_of.html 。alignment_of
类型特征也是现代 C++ 中 STL 的一部分,但在这种特殊情况下,alignof
运算符更易于使用。
推荐阅读
- java - 复制一个HashMap
到另一个 HashMap O(1) 复杂度 (JAVA) - swift - Kotlin-Swift 互操作问题:当从 Swift Code for Release 构建中作为 NSMutableArray 传递时,ArrayList 的计数值错误
- c# - .NET CORE 字典
不消耗 post 请求参数 - c++ - 如何将 std::string_view 转换为 QStringView
- c - 带有数组的分段错误(核心转储)
- javascript - node.js 等待下一步的 db 查询结果
- reactjs - React 如何在运行时注入 js 依赖
- css - 停止 shinydashboardPlus 中的右侧边栏隐藏应用程序的主体
- apache-camel - 如果 MQ 不可用,停止骆驼路由
- c - 有没有办法告诉编译器忽略 C 中的某些代码块?