tl;dr should boost notify_all() be used before or after releasing the lock?
Wikipedia has this comment on signal (in my view similar to broadcast):
it is often also acceptable to release the lock before signalling. Depending on the threading implementation, the ordering of this can have scheduling-priority ramifications. (Some authors[who?] instead advocate a preference for releasing the lock before signalling.) A threading implementation should document any special constraints on this ordering.
The std cpp implementation of the std::condition_variable calls notify_one after releasing the lock:
data = "Example data";
// send data to the worker thread
{
std::lock_guard lk(m);
ready = true;
std::cout << "main() signals data ready for processingn";
}
cv.notify_one();
But when using the boost implementation we can find both variants in the internet (1, 2, 3, p. 127):
boost::interprocess::interprocess_sharable_mutex mutex;
boost::interprocess::interprocess_condition_any cond;
// Producer Process with variants A and B
void producerA() {
const boost::posix_time::ptime abs_time = boost::get_system_time() + boost::posix_time::microseconds(maxLockTime.count());
boost::interprocess::scoped_lock<boost::interprocess::interprocess_sharable_mutex> lock(mutex, boost::interprocess::defer_lock);
if (lock.timed_lock(abs_time)) {
// Write data
// ...
cond.notify_all(); // <--- Notify all consumers
}
}
void producerB() {
const boost::posix_time::ptime abs_time = boost::get_system_time() + boost::posix_time::microseconds(maxLockTime.count());
boost::interprocess::scoped_lock<boost::interprocess::interprocess_sharable_mutex> lock(mutex, boost::interprocess::defer_lock);
if (lock.timed_lock(abs_time)) {
// Write data
// ...
}
cond.notify_all(); // <--- Notify all consumers
}
// Consumer Process
void consumer() {
const boost::posix_time::ptime abs_time = boost::get_system_time() + boost::posix_time::microseconds(maxLockTime.count());
boost::interprocess::scoped_lock<boost::interprocess::interprocess_sharable_mutex> lock(mutex, boost::interprocess::defer_lock);
bool hasNewMessage = cond.timed_wait(lock, abs_time, [=]() { ... });
// Read data
lock.unlock();
}
Is there a definitive answer to which variant is preferred, either producerA
or producerB
. In my local tests both producer work accordingly, but in my question I am interested in worst case scenario where system is heavily loaded.
I ran both producer on my system, there was no notable difference visible.
But I am investigating a bug on another remote system where we observe infinite timeouts on the notify_all()
function call.
Luigsech Ingemar is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.