前言
某些场景下,需要代码只被执行一次,比如单例类的初始化,考虑到多线程安全,需要进行加锁控制。C++11中提供的
call_once可以很好的满足这种需求,使用又非常简单。
一、std::call_once
1、函数声明
函数定义于头文件
<mutex>,call_once保证可调用对象_Fx只被执行一次,即使在多线程场景,函数原型:
template<class _Fn, class... _Args> inline
void (call_once)(once_flag& _Flag, _Fn&& _Fx, _Args&&... _Ax)
_Flag:标志对象,用于指示_Fx是否已调用过_Fx:可调用对象_Ax:传递的参数
使用
call_once注意的事项:
- 如果在调用
call_once的时刻,_Flag指示_Fx已经调用过,那么call_once会立即返回 - 如果在调用
_Fx时抛出了异常,那么异常将传播给call_once的调用方,并且_Flag不会被翻转 - 如果调用正常返回,那么
_Flag被翻转,并保证以同一_Flag对call_once的其他调用立即返回 - 如果有多个线程同时在
_Flag未翻转时调用call_once,那么这些调用将被组成单独全序,并被依次执行
2、std::once_flag
用来表示可调用对象是否成功执行过,
std::once_flag是不允许修改的,其拷贝构造函数和operator=函数都声明为delete,声明如下:
struct once_flag
{ // opaque data structure for call_once()
constexpr once_flag() _NOEXCEPT
: _Opaque(0)
{ // default construct
}
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;
void *_Opaque;
};
注意:还有一个要注意的地方是
once_flag的生命周期,它必须要比使用它的线程的生命周期要长。所以通常定义成全局变量比较好。
3、应用示例
使用
call_once实现一个单例模式,如下:
static std::once_flag oc; // 用于call_once的局部静态变量
Singleton* Singleton::m_instance;
Singleton* Singleton::getInstance() {
std::call_once(oc, [&] () {
m_instance = new Singleton();
});
return m_instance;
}
本文介绍了C++11中的std::call_once函数,用于确保一个函数在多线程环境下仅执行一次,配合once_flag用于线程安全的单例模式示例。
954

被折叠的 条评论
为什么被折叠?



