i am trying to learn the boost library and was going through examples of boost::thread.
The example below illustrates the usage of the boost::lock_guard for thread synchronization, ensuring that the access to std::cout is not concurrent:
#include <boost/thread.hpp>
#include <boost/format.hpp>
#include <iostream>
void wait(const int secs) {
boost::this_thread::sleep(boost::posix_time::seconds(secs));
}
boost::mutex mutex;
void thread1() {
for (int i = 0; i < 10; ++i) {
wait(1); // <-- all works fine if wait is placed here
boost::lock_guard<boost::mutex> lock(mutex);
std::cout << boost::format("thread A here %d\n") % i ;
}
}
void thread2() {
for (int i = 0; i < 10; ++i) {
wait(1); // <-- all works fine if wait is placed here
boost::lock_guard<boost::mutex> lock(mutex);
std::cout << boost::format("thread B here %d\n") % i;
}
}
int main() {
boost::thread t1(thread1);
boost::thread t2(thread2);
t1.join();
t2.join();
}
The results where pretty much what one would expect, i.e. alternating messages by the two threads printed:
thread A here 0
thread B here 0
thread A here 1
thread B here 1
thread A here 2
thread B here 2
thread A here 3
thread B here 3
thread A here 4
thread B here 4
...
However, a small modification -- moving the wait call inside the scope of the lock guard -- led to a surprise:
void thread1() {
for (int i = 0; i < 10; ++i) {
boost::lock_guard<boost::mutex> lock(mutex);
wait(1); // <== !
std::cout << boost::format("thread A here %d\n") % i ;
}
}
void thread2() {
for (int i = 0; i < 10; ++i) {
boost::lock_guard<boost::mutex> lock(mutex);
wait(1); // <== !
std::cout << boost::format("thread B here %d\n") % i;
}
Now either thead1 or thread2 wins the initial "race" for the mutex and then wins again and again on each loop iteration, thereby starving the other thread!
Example output:
thread B here 0
thread B here 1
thread B here 2
thread B here 3
thread B here 4
thread B here 5
thread B here 6
thread B here 7
thread B here 8
thread B here 9
thread A here 0
thread A here 1
thread A here 2
thread A here 3
thread A here 4
thread A here 5
thread A here 6
thread A here 7
thread A here 8
thread A here 9
Can anybody please explain why this is the case?