在有的时候,我们需要在代码中进行一个对象的初始化,但是我们只想要这个对象初始化一次,但是这个函数会被多个线程调用,然后我们需要怎么做呢?
很简单,我们可以在调用初始化对象的函数中定义一个static bool值,当我们调用一次初始化函数的时候,我们就改变bool值的状态,以这个状态作为区分,下次就不会调用初始化函数了;
void fun(){
static bool flag;
if(!flag){
std::thread thSon(initializeFunction);
flag=1;
}
//do something or not
}
C++标准库中提供了更加方便的工具:std::call_once
这个函数的功能和上述差不多,先看他的定义:
template<class _Fn, class... _Args>
inline void (call_once)(once_flag& _Flag, _Fn&& _Fx, _Args&&... _Ax)
注意第一个参数:once_flag&
struct once_flag
{
constexpr once_flag() noexcept
: _Opaque(nullptr){}
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;
void *_Opaque;
};
这个变量的作用和上述的flag是一样的,作为一个标记;
后置的参数是和thread中的一样,但是很奇怪,我们不能像thread一样获取线程的控制权;
看下面这个例子:
std::mutex mtx;
class System {
void SystemInit() {
std::cout << "SystemInit compeleted" << std::endl;
}
public:
void SystemInitOnce() {
static std::once_flag flag;
std::call_once(flag, &System::SystemInit,this);
}
};
int main() {
System system;
for (int i = 0; i < 10; i++) {
std::thread th(&System::SystemInitOnce, &system);
th.detach();
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
其中我们只会调用SystemInit函数一次,但要注意,flag变量一定要是能够区别变化的,比如static变量是每个线程共享的,所以一个线程修改,其他线程调用call_once时就能区别了,否则仍然是调用多次SystemInit