【发布时间】:2019-05-12 12:15:12
【问题描述】:
我正在阅读C++ Concurrency in Action, 2nd Edition X 一书。本书包含一个示例,该示例使用std::call_once() 函数模板和std::once_flag 对象以线程安全的方式提供某种惰性初始化。
这里是本书的简化摘录:
class X {
public:
X(const connection_details& details): connection_details_{details}
{}
void send_data(const data_packet& data) {
std::call_once(connection_init_, &X::open_connection, this);
connection_.send(data); // connection_ is used
}
data_packet receive_data() {
std::call_once(connection_init_, &X::open_connection, this);
return connection_.recv(data); // connection_ is used
}
private:
void open_connection() {
connection_.open(connection_details_); // connection_ is modified
}
connection_details connection_details_;
connection_handle connection_;
std::once_flag connection_init_;
};
上面的代码所做的是延迟连接的创建,直到客户端想要接收数据或有数据要发送。连接是由open_connection() 私有成员函数创建的,而不是由X 的构造函数创建的。构造函数仅保存连接详细信息以便以后能够创建连接。
上面的open_connection() 成员函数被调用一次,到目前为止一切正常。在单线程上下文中,这将按预期工作。但是,如果多个线程在同一个对象上调用send_data() 或receive_data() 成员函数怎么办?
显然,open_connection() 中的connection_ 数据成员的修改/更新与它在send_data() 或receive_data() 中的任何使用都不同步。
std::call_once() 是否会阻塞第二个线程,直到第一个线程从 std::call_once() 返回?
X第 3.3.1. 节:在初始化期间保护共享数据
【问题讨论】:
-
曾经有一个关于 Meyers Singleton 方法的有趣讨论:SO: Is Meyers' implementation of the Singleton pattern thread safe? 这可能很有趣。
-
std::call_once确实与同一once_flag实例上对std::call_once的其他调用同步。这就是重点。
标签: c++ multithreading c++11 initialization std-call-once