C++ 并发编程 | std::call_once


前言

某些场景下,需要代码只被执行一次,比如单例类的初始化,考虑到多线程安全,需要进行加锁控制。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 被翻转,并保证以同一 _Flagcall_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;
}
  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误通常发生在使用C++11标准的程序中,因为`std::this_thread`是C++11中引入的线程库头文件,需要在头文件中包含`<thread>`。如果您的程序中没有包含该头文件,则编译器会提示此错误。可以将以下代码添加到您的头文件中: ```cpp #include <thread> #include <chrono> ``` 如果您已经包含了这两个头文件,那么请确保您的编译器支持C++11标准。您可以通过在编译器命令行中添加`-std=c++11`或更高版本的选项来启用C++11标准。 ### 回答2: 这个错误是由于未声明std::this_thread导致的。std::this_thread是C++11中的一个线程库,可以用于控制线程的行为。在这个错误中,65代表代码的行号,而std::this_thread::sleep_for(std::chrono::minutes(10))是一段用于让当前线程休眠10分钟的代码。 解决这个错误的方法是包含正确的头文件。在C++中,使用std::this_thread需要包含<thread>和<chrono>这两个头文件。请确保在使用这段代码之前已经包含了这两个头文件,否则编译器就无法识别std::this_thread的定义。 例如,在代码的顶部添加以下两行代码: ```cpp #include <thread> #include <chrono> ``` 这样就可以解决std::this_thread未声明的错误。然后,编译器就能够正确识别std::this_thread::sleep_for(std::chrono::minutes(10))这段代码,并执行线程的休眠操作。 ### 回答3: ‘std::this_thread’ has not been declared 65 | std::this_thread::sleep_for(std::chrono::minutes(10)) 是一个编译错误信息,意思是在代码的第65行,标准库std::this_thread没有被声明。 编译错误可能是由于以下几个原因造成的: 1. 忘记包含相关的头文件:要使用std::this_thread的话,需要包含<thread>头文件。请确保在你的代码中包含了该头文件。 2. 编译器不支持标准库:某些较老的编译器可能不支持std::this_thread,或者支持的标准库版本较低。在这种情况下,你可能需要升级你的编译器或使用一个支持该特性的编译器。 3. 编译器选项配置错误:检查编译器选项是否正确设置。有时候编译器可能没有正确配置,导致无法识别std::this_thread。确保编译器选项中包含了正确的标准库路径和头文件路径。 4. 命名空间错误:请检查代码中是否正确使用了std命名空间。如果你没有在代码中显式指定命名空间,或者正在使用一个自定义的命名空间,请确保正确地使用std::this_thread。 总之,检查以上几个原因,通常可以解决‘std::this_thread’ has not been declared 65 | std::this_thread::sleep_for(std::chrono::minutes(10)) 这个编译错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值