C++ 如何使用 std::atomic<>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30761225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:48:44  来源:igfitidea点击:

How to use std::atomic<>

c++multithreadingc++11atomic

提问by mans

I have a class that I want to use in different threads and I think I may be able to use std::atomicthis way:

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

class A
{
    int x;

public:
    A()
    {
        x=0;
    }

    void Add()
    {
        x++;
    }

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

and in my code:

在我的代码中:

  std::atomic<A> a;

and in a different thread:

并在不同的线程中:

  a.Add();

and

  a.Sub();

but I am getting an error that a.Add()is not known. How can I solve this?

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

Is there any better way to do this?

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

Please note that it is an example, and what I want is to make sure that access to class A is thread-safe, so I can not use

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

std::atomic<int> x;

How can I make a class thread-safe using std::atomic?

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

回答by Unda

You need to make the xattribute atomic, and not your whole class, as followed:

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

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

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

The error you get in you original code is completely normal: there is no std::atomic<A>::Addmethod (see here) unless you provide a specialization for std::atomic<A>.

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

Referring your edit: you cannot magically make your class Athread safe by using it as template argument of std::atomic. To make it thread safe, you can make its attributes atomic (as suggested above and provided the standard library gives a specialization for it), or use mutexes to lock your ressources yourself. See the mutexheader. For example:

引用您的编辑:您不能通过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 ...
  }

};

回答by ivanw

Declare the class member xas atomic, then you don't have to declare the object as atomic:

将类成员声明x为原子的,那么您不必将对象声明为原子的:

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

回答by a_pradhan

The .operator can be used on an object to call its class's member function, not some other class's member function (unless you explicitly write the code that way).

.操作员可以在对象上用来调用其类的成员函数,而不是一些其他类的成员函数(除非你明确地写代码的方式)。

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

As the answer by @ivanw mentions, make std::atomic<int>a member of your class instead and then use it.

正如@ivanw 所提到的,std::atomic<int>请改为成为您的班级成员,然后使用它。

Here is another example:

这是另一个例子:

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.

回答by Jon Watte

I think the problem with the answers above is that they don't explain what I think is, at a minimum, an ambiguity in the question, and most likely, a common threaded development fallacy.

我认为上述答案的问题在于,它们并没有解释我所认为的,至少是问题中的歧义,最有可能是一个常见的线程开发谬误。

You can't make an object "atomic" because the interval between two functions (first "read x" and then later "write x") will cause a race with other uses. If you think you need an "atomic" object, then you need to carefully design the API and member functions to expose now to begin and commit updates to the object.

您不能使对象成为“原子”对象,因为两个函数之间的间隔(首先“读取 x”,然后是“写入 x”)会导致与其他用途的竞争。如果您认为您需要一个“原子”对象,那么您需要仔细设计 API 和成员函数以立即公开以开始并提交对对象的更新。

If all you mean by "atomic" is "the object doesn't corrupt its internal state," then you can achieve this through std::atomic<>for single plain-old-data types that have no invariant between them (a doesn't depend on b) but you need a lock of some sort for any dependent rules you need to enforce.

如果您所说的“原子”只是“对象不会破坏其内部状态”,那么您可以通过std::atomic<>它们之间没有不变的单个普通旧数据类型来实现这一点(a 不依赖于 b)但是对于需要强制执行的任何相关规则,您都需要某种锁定。