如何使用标准::原子<>



我有一个类,我想在不同的线程中使用,我想我可以这样使用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使类线程安全

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

class A
{
    std::atomic<int> x;
    public:
      A() {
        x=0;
      }
      void Add() {
        x++;
      }
      void Sub() {
        x--;
      }     
};

你在原始代码中得到的错误是完全正常的:没有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 ...
  }
};

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

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

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

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.

我认为以上答案的问题在于它们没有解释我认为的问题,至少是一个模棱两可的问题,而且很可能是一个常见的线程开发谬误。

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

如果你所说的"原子"是指"对象不会破坏它的内部状态",那么你可以通过std::atomic<>来实现单一的纯旧数据类型,它们之间没有不变量(a不依赖于b),但你需要某种类型的锁来执行任何依赖规则

相关内容

  • 没有找到相关文章

最新更新