/**
* This blog entry focuses on the use of a mutex.
*/
// Obviously required for using threads.
#include <boost/thread.hpp>
// Output through cout can be garbled when using
// threads, so in this example I'm going to guard
// against cout interruption.
#include <iostream>
// Using this to put together output strings.
#include <sstream>
/**
* If you are building this example, try commenting
* this out and see what happens to the output.
* It's hard to tell at times but it is indeed
* garbled at points.
*/
#define DO_LOCK
// We have a singular mutex that guards cout. This
// is only used from PrintLocker.
static boost::mutex printMutex;
/**
* The PrintLocker. This is an RAII class that
* locks a mutex (if it can) and then unlocks it
* upon destruction. This is very exception
* savvy and will earn you extra points with your
* colleagues.
*/
struct PrintLocker
{
PrintLocker()
{
#if defined DO_LOCK
printMutex.lock();
#endif
}
~PrintLocker()
{
#if defined DO_LOCK
printMutex.unlock();
#endif
}
};
/**
* This is the only print mechanism this program
* has. It guards the cout access.
*/
void print(std::string const& stringOutput)
{
// Check it out, by creating this object
// you lock the mutex (if you can get it).
// If you can't get it, the thread yields
// and allows other active threads to run.
PrintLocker pl;
// Once you have the lock, feel free to
// print to standard out.
std::cout << stringOutput << std::endl;
// At the end, the object pl will be
// destroyed. Remember that in the destructor
// the mutex will unlock. If an exception
// is thrown within cout then pl will still
// be destroyed and the mutex unlocked.
}
/**
* This is just a convenience function used
* to put together output strings via a string
* stream.
*/
template <typename T1, typename T2, typename T3>
std::string getString(T1 const& t1, T2 const& t2, T3 const& t3)
{
std::stringstream ss;
ss << t1 << t2 << t3;
return ss.str();
}
/**
* The new thread function, which is invoked whenever
* we create a new boost thread. It will pause randomly
* while iterating 10 times. The random pauses help us
* when trying to expose race conditions (just comment
* out the #define DO_LOCK).
*/
void newThread(int threadId)
{
print(getString("START Thread #", threadId, ""));
for(int i=0; i<10; ++i)
{
print(getString(i, "th Iteration, Thread #", threadId));
boost::posix_time::seconds pauseTime( rand() % 2 );
boost::this_thread::sleep(pauseTime);
}
print(getString("END Thread #", threadId, ""));
}
int main(int argc, char** argv)
{
boost::thread t1(newThread, 1);
boost::thread t2(newThread, 2);
boost::thread t3(newThread, 3);
t1.join();
t2.join();
t3.join();
}
/**
* In conclusion, boost mutexes are pretty normal.
* They provide a nice wrapper around whatever threading
* system is already present on your system.
*/
Wednesday, May 8, 2013
Boost Threads (Part 2)
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment