auto dispatchable = std::make_shared<mt::TestDispatchable>([&dispatcher]() { delete dispatcher; });
dispatcher = new md::ThreadedDispatcher("Death thread", dispatchable);
dispatchable->trigger();
}
invokes undefined behaviour. The read for “delete dispatcher” (which happens in the thread created in the ThreadedDispatcher) conflicts with the write to dispatcher (after ThreadedDispatcher's constructor has run).
The read for “delete dispatcher” is triggered by dispatchable->trigger(), but dispatchable->trigger() is *not* a synchronisation point - there are no mutexes or memory barriers involved.
std::atomic<> is exactly the tool required to solve this. (I guess we could also use std::atomic_thread_fence, but that's essentially a larger hammer for the same thing).
This code:
{ :ThreadedDispat cher* dispatcher;
md:
auto dispatchable = std::make_ shared< mt::TestDispatc hable>( [&dispatcher] () { delete dispatcher; });
dispatcher = new md::ThreadedDis patcher( "Death thread", dispatchable);
dispatchabl e->trigger( );
}
invokes undefined behaviour. The read for “delete dispatcher” (which happens in the thread created in the ThreadedDispatcher) conflicts with the write to dispatcher (after ThreadedDispatc her's constructor has run).
The read for “delete dispatcher” is triggered by dispatchable- >trigger( ), but dispatchable- >trigger( ) is *not* a synchronisation point - there are no mutexes or memory barriers involved.
std::atomic<> is exactly the tool required to solve this. (I guess we could also use std::atomic_ thread_ fence, but that's essentially a larger hammer for the same thing).