简体   繁体   English

如何使用std :: atomic <>

[英]How to use std::atomic<>

I have a class that I want to use in different threads and I think I may be able to use std::atomic this 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. 但我收到a.Add()未知的错误。 How can I solve this? 我怎么解决这个问题?

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创建一个类线程安全的?

You need to make the x attribute 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>::Add method (see here ) unless you provide a specialization for std::atomic<A> . 您在原始代码中获得的错误是完全正常的:除非您为std::atomic<A>提供特化,否则没有std::atomic<A>::Add方法(请参见此处 )。

Referring your edit : you cannot magically make your class A thread safe by using it as template argument of std::atomic . 引用你的编辑 :你不能通过使用它作为std::atomic模板参数来神奇地使你的class A线程安全。 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 mutex header. 请参阅互斥锁标头。 For example: 例如:

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 ...
  }

};

Declare the class member x as atomic, then you don't have to declare the object as atomic: 将类成员x声明为原子,然后您不必将对象声明为原子:

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

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.

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. 你不能使一个对象“原子”,因为两个函数之间的间隔(首先是“读取x”,然后是“写入x”)将导致具有其他用途的竞赛。 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. 如果您认为需要“原子”对象,那么您需要仔细设计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 doesn不依赖于b)但是你需要对你需要强制执行的任何依赖规则进行某种锁定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM