I was reading through a Boost Mutex tutorial on drdobbs.com, and found this piece of code:
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex io_mutex;
void count(int id)
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": " <<
i << std::endl;
}
}
int main(int argc, char* argv[])
{
boost::thread thrd1(
boost::bind(&count, 1));
boost::thread thrd2(
boost::bind(&count, 2));
thrd1.join();
thrd2.join();
return 0;
}
Now I understand the point of a Mutex is to prevent two threads from accessing the same resource at the same time, but I don't see the correlation between io_mutex and std::cout. Does this code just lock everything within the scope until the scope is finished?
std::coutis a global object, so you can see that as a shared resource. If you access it concurrently from several threads, those accesses must be synchronized somehow, to avoid data races and undefined behavior.Perhaps it will be easier for you to notice that concurrent access occurs by considering that:
Is actually equivalent to:
Which means you are calling a function that operates on the
std::coutobject, and you are doing so from different threads at the same time.std::coutmust be protected somehow. But that's not the only reason why thescoped_lockis there (keep reading).Yes, it locks
io_mutexuntil the lock object itself goes out of scope (being a typical RAII wrapper), which happens at the end of each iteration of your for loop.Why is it needed? Well, although in C++11 individual insertions into
coutare guaranteed to be thread-safe, subsequent, separate insertions may be interleaved when several threads are outputting something.Keep in mind that each insertion through
operator <<is a separate function call, as if you were doing:The fact that
operator <<returns the stream object allows you to chain the above function calls in a single expression (as you have done in your program), but the fact that you are having several separate function calls still holds.Now looking at the above snippet, it is more evident that the purpose of this scoped lock is to make sure that each message of the form:
Gets printed without its parts being interleaved with parts from other messages.
Also, in C++03 (where insertions into
coutare not guaranteed to be thread-safe) , the lock will protect thecoutobject itself from being accessed concurrently.