如何使用std :: atomic <>

man*_*ans 29 c++ multithreading atomic c++11

我有一个类,我想在不同的线程中使用,我想我可以使用std::atomic这种方式:

class A
{
    int x;

public:
    A()
    {
        x=0;
    }

    void Add()
    {
        x++;
    }

    void Sub()
    {
        x--;
    }     
};
Run Code Online (Sandbox Code Playgroud)

在我的代码中:

  std::atomic<A> a;
Run Code Online (Sandbox Code Playgroud)

并在另一个线程中:

  a.Add();
Run Code Online (Sandbox Code Playgroud)

  a.Sub();
Run Code Online (Sandbox Code Playgroud)

但我收到一个a.Add()未知的错误.我怎么解决这个问题?

有没有更好的方法来做到这一点?

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

std::atomic<int> x;
Run Code Online (Sandbox Code Playgroud)

如何使用线程安全的类std::atomic

Und*_*nda 37

您需要使x属性为atomic,而不是整个类,如下所示:

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

    public:
      A() {
        x=0;
      }
      void Add() {
        x++;
      }
      void Sub() {
        x--;
      }     
};
Run Code Online (Sandbox Code Playgroud)

你在原始代码中得到的错误是完全正常的:没有std::atomic<A>::Add方法(见这里),除非你提供专业化std::atomic<A>.

参考你的编辑:你不能通过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 ...
  }

};
Run Code Online (Sandbox Code Playgroud)

  • 我会提取`std :: lock_guard`而不是手动锁定和释放. (15认同)
  • @ Virus721是的,这就是`std :: lock_guard`背后的想法. (4认同)
  • @ LukeB.Lin_guard背后的想法是依靠自动变量的析构函数在退出作用域时被调用以释放锁定,就像使用RAII一样? (2认同)

小智 5

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

class A
{  
   std::atomic<int> x;
};
Run Code Online (Sandbox Code Playgroud)

  • 这就像问"如何用套筒扳手拧下这个飞利浦头螺钉?" 螺丝刀和扳手都是翻转工具的工具,但其中一个不适合工作.您需要一个合适的互斥锁或其他更重要的同步构造,以保护整个矢量. (3认同)
  • @mans只要您不从多个线程访问同一元素,就可以安全地从多个线程访问std :: vector的不同元素。这是标准库的保证。 (2认同)

a_p*_*han 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
Run Code Online (Sandbox Code Playgroud)

正如@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.
Run Code Online (Sandbox Code Playgroud)