use*_*581 7 mutex atomic object thread-safety c++11
我想知道,在C++ 11中只能将原始数据类型声明为std :: atomic吗?例如,是否有可能声明库类对象被"原子地"变异或访问?
例如,我可能有
using namespace std::chrono;
time_point<high_resolution_clock> foo;
// setter method
void set_foo() {
foo = high_resolution_clock::now();
}
// getter method
time_point<high_resolution_clock> get_foo() {
return foo;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果在不同的线程中调用这些setter和getter方法,我认为这可能会导致未定义的行为.如果我可以声明foo之类的话会很好:
std::atomic<time_point<high_resolution_clock>> foo;
Run Code Online (Sandbox Code Playgroud)
......所以foo上的所有操作都将以原子方式进行.在我的项目的应用程序中,可能有数百个这样的foo变量在几十个类中声明,我觉得使对象变异并访问"原子"可以说更方便,而不必声明和lock_guard遍布整个地方的互斥体.
这是不可能的,还是有更好的方法,或者我真的必须在任何地方使用互斥锁和lock_guard吗?
更新:
atomic<>不限于原始类型。允许与可简单复制的类型atomic<>一起使用。来自c++11 标准的第 29.5 节原子类型(也在 中说明):Tstd::atomic
有一个通用类模板原子。模板参数 T 的类型应该是可简单复制的(3.9)。
如果需要原子访问的对象不能与 一起使用,atomic<>则定义新对象,其中包含原始对象和std::mutex. 这意味着lock_guard<>仅在新线程安全对象的 getter 和 setter 中使用,而不是在整个代码中乱七八糟。Atemplate或许能够定义所需的线程安全机制:
template <typename T>
class mutable_object
{
public:
mutable_object() : t_() {}
explicit mutable_object(T a_t) : t_(std::move(a_t)) {}
T get() const
{
std::lock_guard<std::mutex> lk(mtx_);
return t_;
}
void set(T const& a_t)
{
std::lock_guard<std::mutex> lk(mtx_);
t_ = a_t;
}
private:
T t_;
mutable std::mutex mtx_;
};
using mutable_high_resolution_clock =
mutable_object<std::chrono::time_point<
std::chrono::high_resolution_clock>>;
using mutable_string = mutable_object<std::string>;
mutable_high_resolution_clock c;
c.set(std::chrono::high_resolution_clock::now());
auto c1 = c.get();
mutable_string s;
s.set(std::string("hello"));
auto s1 = s.get();
Run Code Online (Sandbox Code Playgroud)