c++ - threats - Cómo usar std:: atomic<>
threads c++ stack overflow (4)
Tengo una clase que quiero usar en diferentes hilos y creo que puedo usar std::atomic
esta manera:
class A
{
int x;
public:
A()
{
x=0;
}
void Add()
{
x++;
}
void Sub()
{
x--;
}
};
y en mi código:
std::atomic<A> a;
y en un hilo diferente:
a.Add();
y
a.Sub();
pero a.Add()
un error que no se conoce a.Add()
. ¿Como puedo resolver esto?
¿Hay alguna manera mejor de hacer esto?
Tenga en cuenta que es un ejemplo, y lo que quiero es asegurarme de que el acceso a la clase A sea seguro para subprocesos, por lo que no puedo usar
std::atomic<int> x;
¿Cómo puedo hacer que una clase sea segura para subprocesos usando std::atomic
?
Creo que el problema con las respuestas anteriores es que no explican lo que creo que es, como mínimo, una ambigüedad en la pregunta y, muy probablemente, una falacia de desarrollo común.
No se puede hacer un objeto "atómico" porque el intervalo entre dos funciones (primero "leer x" y luego "escribir x") causará una carrera con otros usos. Si cree que necesita un objeto "atómico", debe diseñar cuidadosamente la API y las funciones de los miembros para exponer ahora para comenzar y confirmar las actualizaciones del objeto.
Si todo lo que quiere decir con "atómico" es "el objeto no corrompe su estado interno", entonces puede lograrlo a través de std::atomic<>
para los tipos únicos de datos antiguos que no tienen invariante entre ellos (a doesn no dependa de b) pero necesita algún tipo de bloqueo para las reglas dependientes que necesita hacer cumplir.
Debe hacer que el atributo x
atómico, y no toda su clase, como se indica a continuación:
class A
{
std::atomic<int> x;
public:
A() {
x=0;
}
void Add() {
x++;
}
void Sub() {
x--;
}
};
El error que recibe en su código original es completamente normal: no hay un método std::atomic<A>::Add
(consulte here ) a menos que proporcione una especialización para std::atomic<A>
.
Referencia a su edición : no puede mágicamente hacer que su hilo de class A
seguro usándolo como un argumento de plantilla de std::atomic
. Para hacer que el hilo sea seguro, puede hacer que sus atributos sean atómicos (como se sugirió anteriormente y siempre que la biblioteca estándar le ofrezca una especialización), o usar mutexes para bloquear sus recursos usted mismo. Ver el encabezado de mutex mutua. Por ejemplo:
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 el miembro de la clase x
como atómico, entonces no tiene que declarar el objeto como atómico:
class A
{
std::atomic<int> x;
};
El .
el operador se puede usar en un objeto para llamar a la función miembro de su clase, no a la función miembro de otra clase (a menos que escriba explícitamente el código de esa manera).
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
Como lo indica la respuesta de @ivanw, en su lugar, haga de std::atomic<int>
un miembro de su clase y luego utilícelo.
Aquí hay otro ejemplo:
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.