C++11 once_flag與call_once組合,實現調用一次函數

頭文件

#include <mutex>

once_flag結構

std::once_flag實例的狀態,指示所關聯的函數尚未被調用。
其構造函數擁有constexpr指定符,以帶有靜態存儲時間段的實例,作爲靜態初始化階段的一部分被構造,避免競爭條件和初始化順序問題。

struct once_flag
{
	constexpr once_flag() noexcept : _Opaque(0){}
	once_flag(const once_flag&) = delete;
	once_flag& operator=(const coce_flag&) = delete;
	void *_Opaque;
}

call_once函數模板

在同一std::once_flag對象上,std::call_once調用被序列化。
當且僅當_Fx的調用返回而無異常,std::call_once的調用有效。
若在同一std::once_flag對象上,之前未有過有效的std::call_once調用,參數_Fx(或其副本)如同通過INVOKE(_Fx, _Ax)一樣被調用。
如果在同一std::once_flag對象上,之前有過有效的std::call_once,對std::call_once的後續調用直接返回而不執行_Fx。

template<typename _Fn, typename... _Args>
inline void call_once(once_flag& _Flag, _Fn&& _Fx, _Args&&... _Ax);

用法

有時對於一類對象,只需初始化一次環境,可以採用類似的封裝方式:

#include <mutex>

class Module
{
public:
	Module() {}
	~Module() {}
	void init()
	{
		static std::once_flag once_init;
		std::call_once(once_init, openLibs);
	}
private:
	static void openLibs() {}
};

錯誤用法

在上述的openLibs函數中,再次間接通過std::call_once調用自己,會導致棧溢出錯誤。這是由於未完成一次有效調用,還未改變std::once_flag的狀態,仍然出現openLibs被多次調用的情況。

參考資料

[1] C++併發編程實戰[M]. [美]Anthony Williams著;周全等譯. 北京:人民郵電出版社,2015

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章