如何使用std :: atomic<>

时间:2015-06-10 15:47:27

标签: c++ multithreading c++11 atomic

我有一个我想在不同主题中使用的类,我想我可以这样使用std::atomic

class A
{
    int x;

public:
    A()
    {
        x=0;
    }

    void Add()
    {
        x++;
    }

    void Sub()
    {
        x--;
    }     
};

在我的代码中:

  std::atomic<A> a;

并在另一个主题中:

  a.Add();

  a.Sub();

但是我收到a.Add()未知的错误。我该如何解决这个问题?

有没有更好的方法呢?

请注意,这是一个示例,我想要的是确保对A类的访问是线程安全的,所以我不能使用

std::atomic<int> x;

如何使用std::atomic创建一个线程安全的类?

4 个答案:

答案 0 :(得分:34)

您需要将x属性设为原子,而不是整个类,如下所示:

class A
{
    std::atomic<int> x;

    public:
      A() {
        x=0;
      }
      void Add() {
        x++;
      }
      void Sub() {
        x--;
      }     
};

您在原始代码中遇到的错误完全正常:除非您为std::atomic<A>::Add提供专业化,否则没有std::atomic<A>方法(请参阅here)。

参考您的修改:您不能将class A线程用作std::atomic的模板参数,从而神奇地保证您的class A { std::atomic<int> x; std::vector<int> v; std::mutex mtx; void Add() { x++; } void Sub() { x--; } /* Example method to protect a vector */ void complexMethod() { mtx.lock(); // Do whatever complex operation you need here // - access element // - erase element // - etc ... mtx.unlock(); } /* ** Another example using std::lock_guard, as suggested in comments ** if you don't need to manually manipulate the mutex */ void complexMethod2() { std::lock_guard<std::mutex> guard(mtx); // access, erase, add elements ... } }; 线程安全。为了使其线程安全,您可以将其属性设置为原子(如上所述并提供标准库为其提供特化),或使用互斥锁自行锁定您的资源。请参阅mutex标题。例如:

.big{
        background-color: red;
    }
@media screen and (max-width: 300px) {
    .big{
        background-color: lightblue;
    }
}

答案 1 :(得分:5)

将类成员x声明为原子,然后您不必将该对象声明为原子:

class A
{  
   std::atomic<int> x;
};

答案 2 :(得分:5)

可以在一个对象上使用.运算符来调用其类的成员函数,而不是其他类的成员函数(除非您以这种方式明确地编写代码)。

std::atomic<A> a ;
a.Add(); // Here, a does not know what Add() is (a member function of the type parameter)
         // It tries to call Add() method of its own class i.e. std::atomic
         // But std::atomic has no method names Add or Sub

正如@ivanw提到的答案,让std::atomic<int>成为你班级的一员,然后再使用它。

这是另一个例子:

template <typename T> class A
{};

class B { public: void hello() { std::cout << "HELLO!!!"; } };

A<B> a ;
a.hello(); // This statement means that call a's hello member function
           // But the typeof(a) which is A does not have such a function
           // Hence it will be an error.

答案 3 :(得分:1)

我认为上述答案的问题在于,他们不能解释我的想法,至少是问题的模糊性,而且很可能是一个共同的线程发展谬误。

你不能制作一个对象&#34; atomic&#34;因为两个函数之间的间隔(第一个&#34;读取x&#34;然后是&#34;写x&#34;)将导致具有其他用途的竞赛。如果你认为你需要一个&#34; atomic&#34;对象,那么你需要仔细设计API和成员函数,以便现在公开以开始并提交对象的更新。

如果你的意思是&#34; atomic&#34;是&#34;对象不会破坏其内部状态,&#34;那么你可以通过std::atomic<>来实现这一点,因为它们之间没有不变量的单个普通旧数据类型(不依赖于b)但是你需要为你需要的任何依赖规则锁定一些执行。