Object C++;11只能将原始数据类型声明为原子数据类型吗?

Object C++;11只能将原始数据类型声明为原子数据类型吗?,object,c++11,thread-safety,mutex,atomic,Object,C++11,Thread Safety,Mutex,Atomic,我想知道,在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

我想知道,在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;
}
使用名称空间std::chrono;
时间点foo;
//塞特法
void set_foo(){
foo=高分辨率时钟::现在();
}
//吸气剂法
时间点获取时间点{
返回foo;
}
但是,如果在不同的线程中调用这些setter和getter方法,我认为这可能会导致未定义的行为。如果我可以声明foo类似于:

std::atomic<time_point<high_resolution_clock>> foo;
std::原子foo;
…这样所有关于foo的行动都将以原子方式进行。在我项目的应用程序中,可能有数百个这样的foo变量在几十个类中声明,我觉得让对象变异并访问“原子”会更方便,而不必到处声明和锁定互斥锁

这是不可能的,还是有更好的方法,或者我真的必须在任何地方使用互斥锁和锁保护

更新

  • 有人要吗?我一直在网络上寻找合适的信息,但是使用atomic的例子太少了,我不能确定它的应用范围
  • 原子的
不限于基本类型。允许将
atomic
与类型
T
一起使用,即。根据c++11标准第29.5节原子类型(也在中说明):

有一个通用类模板原子。模板参数T的类型应该是可复制的(3.9)

如果需要原子访问的对象不能与
atomic
一起使用,则定义新对象,其中包含原始对象和
std::mutex
。这意味着,
lock\u-guard
仅在新线程安全对象的getter和setter中使用,并且不会在整个代码中乱放。
模板
可能能够定义所需的螺纹安全机构:

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();
模板
类可变对象
{
公众:
可变_对象():t_u(){}
显式可变_对象(T a_T):T_(std::move(a_T)){
T get()常量
{
标准:锁紧保护lk(mtx);
返回t_;
}
空集(常数和空集)
{
标准:锁紧保护lk(mtx);
t_u=a_ut;
}
私人:
T!;
可变std::互斥mtx;
};
使用可变高分辨率时钟=
可变对象>;
使用可变_字符串=可变_对象;
可变高分辨率时钟c;
c、 set(std::chrono::high_resolution_clock::now());
自动c1=c.get();
可变_字符串;
s、 set(std::string(“hello”);
自动s1=s.get();

原子仅限于可复制的类(即没有自定义复制构造函数的类,其成员也可复制)

这一要求对原子具有巨大的优势:

  • 没有原子操作可以抛出,因为构造函数抛出了
  • 所有原子都可以用锁(自旋锁或互斥锁)和memcpy来复制数据
  • 所有原子都有一个有限的运行时间(有界)

后者特别有用,因为原子有时是使用自旋锁实现的,并且非常希望在持有自旋锁时避免无界任务。如果允许使用任何构造函数,那么实现往往需要依赖于完整的互斥锁,对于非常小的关键部分,互斥锁比自旋锁慢。

std::atomic对于断开的线程代码来说不是一种解决方法。如果另一个线程调用setter,那么不管第一个线程调用什么,它都将从getter获取一个垃圾值。