使用互斥元进行线程安全的延迟初始化
像下面这段代码一样的朴素的转换,会引起使用该资源的线程产生不必要的序列化。这是因为每个线程都必须等待互斥元,以检查资源是否已经被初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13
   | std::shared_ptr<Resource> resource_ptr; std::mutex m;
  void foo() {     std::unique_lock<std::mutex> lk(m);     if (!source_ptr)     {         resource_ptr.reset(new Resource);      }     lk.unlock();     resource_ptr->do_something(); }
   | 
 
语气锁定互斥元并且显式地检查指针,还不如每个线程都可以用 std::call_once,到 call_once 返回时,指针将会被某个线程初始化(以完全同步的方式),这样就安全了。使用 std::call_once 比显式地使用互斥元通常会有更低的开销,特别是初始化已经完成的时候。
1 2 3 4 5 6 7 8 9 10 11 12 13
   | std::sharef_ptr<Resource> resource_ptr; std::once_flag resource_flag;
  void init_resource() { 	resource_ptr.reset(new Resource); }
  void foo() {     std::call_once(resource_flag, init_resource);     resource_ptr->do_something(); }
   | 
 
std::call_once() 可以容易地用于类成员的延迟出初始化:
1 2 3 4 5
   | void X::call() { 	std::call_once(init_flag, &X:init, this); 	do_something(); }
   |