I have an std::vector that is used to pass message to a thread. The vector is protected by a mutex:
vector<int> messages;
std::mutex m;
void postmessage (int msg) {
{
std::unique_lock Lock (m);
messages.push_back (msg);
}
}
When the thread is woken up, it grabs the entire message queue like this:
const auto my_messages = [this] {
std::unique_lock Lock (m);
return move (messages);
} ();
It then processes my_messages. Questions:
Is this guaranteed to leave the vector in an empty state? In other words, is this an application of constructor (7) on cppreference that guarantees that the vector is left empty?
Are the operations on messages guaranteed to be completed before the mutex is unlocked? In other words, is this thread-safe?
- Is this guaranteed to leave the vector in an empty state?
Yes, the returned value is move-constructed from messages, therefore messages is empty as you have correctly deduced.
This does not apply to all standard library types, so be careful -- some containers leave the source in an "unspecified but valid" state, which means it is only safe to perform actions on the source that have no preconditions. In those cases you can safely clear() the source to ensure that it is empty; clear() has no preconditions, and leaves the container empty.
- Are the operations on
messagesguaranteed to be completed before the mutex is unlocked? In other words, is this thread-safe?
Yes, this is safe. It seems you are most worried about the code that "grabs" the message queue.
The crux of this issue is whether messages is used after Lock is destructed. The answer is no, it is not used.
Construction of the returned value must complete before any locals are destructed. Why? Because you might use a local to construct the return value!
std::vector<int> foo() {
std::vector<int> x;
return x;
}
x can't be destructed before the return value is constructed or there is undefined behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With