¿Puede std::atomic_flag ser eliminado de forma segura después de llamar a notify_all?
En mi código, quiero usar un std::atomic_flag
para sincronizar dos hilos. Específicamente, me gustaría usar las nuevas características wait
y notify_all
que se introducen en C++20.
En resumen: un hilo está esperando a que la bandera esté lista mientras que otro hilo establecerá la bandera y emitirá la notificación. Sin embargo, la complicación es que el atomic_flag
vive en la pila y se destruirá después de la notificación, mientras que el primer hilo aún puede estar en la llamada a wait
.
Básicamente, tengo algo equivalente al siguiente fragmento de código:
“`c++
#include <atomic>
#include <thread>
int main(int, char**)
{
auto t = std::thread{};
<pre><code>{
auto f = std::atomic_flag{};
t = std::thread{[&f] { f.wait(false); }};
// Asegura que 't' está esperando en 'f' (no es una garantía del 100%, pero se entiende el punto)
std::this_thread::sleep_for(std::chrono::milliseconds{50});
f.test_and_set();
f.notify_all();
} // <— 'f' se destruye aquí pero 't' podría seguir en la llamada a wait
t.join();
return 0;
</code></pre>
}
“`
En el pasado, he utilizado boost::latch
para situaciones como esta y sé por experiencia que este patrón casi siempre causará un cierre inesperado o una aserción. Sin embargo, reemplazar boost::latch
con std::atomic_flag
no ha resultado en ningún cierre inesperado, aserción o bloqueo.
Mi pregunta es: ¿es seguro destruir un std::atomic_flag
después de llamar a notify_all
(es decir, con hilos despertados potencialmente aún en el método wait
)?
davy.ai
No, no es seguro destruir un
std::atomic_flag
después de una llamada anotify_all
, ya que podría haber hilos esperando en la bandera en el momento de la destrucción. El comportamiento en esta situación es indefinido y puede resultar en fallos, bloqueos u otros problemas. Se recomienda utilizar un primitivo de sincronización diferente, comostd::condition_variable
, que permita una señalización segura entre hilos.