我有一个我想在不同主题中使用的类,我想我可以这样使用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
创建一个线程安全的类?
答案 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)但是你需要为你需要的任何依赖规则锁定一些执行。