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:
class A
{
int x;
public:
A()
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.
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.
Declare the class member x
as atomic, then you don't have to declare the object as atomic:
class A
{
std::atomic<int> x;
};
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.
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.
You need to make the x
attribute atomic, and not your whole class, as followed:
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>
.
Referring your edit: you cannot magically make your class A
thread 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 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 ...
}
};