Thursday, May 9, 2013

Boost Threads (Part 3)


/**
 * This is my third small example for boost
 * threads. This time, I'm covering the difference
 * between a regular mutex and a "recursive"
 * mutex.
 *
 * I happened by this topic while googling the
 * words, "Reentrant Function". It caused me to
 * ask a question: What happens when a recursive
 * function attempts to lock the same mutex?
 *
 * This example shows how it can be done and how
 * it can lock up (if you use the wrong mutex).
 * Ultimately I wrote this example before finally
 * looking up the definition to reentrancy. It
 * (reentrant mutex) is a "mutual exclusion,
 * recursive lock mechanism". Let's see how it
 * is employed.
 */

// Obviously required for using threads (mutex,
// recursive mutex, etc)
#include <boost/thread.hpp>

// Needed for print statements.
#include <iostream>


/**
 * So if you want to deadlock this program, just
 * define the following macro. It makes the
 * fibonacci example instantiate a regular non-
 * recursive mutex.
 */
#if defined WANT_TO_DEADLOCK
typedef boost::mutex fibonacci_mutex;
#else

/**
 * By default this recursive mutex is defined.
 */
typedef boost::recursive_mutex fibonacci_mutex;
#endif


int fibonacci(int i)
{
static fibonacci_mutex mtx;

// Because this is a recursive method (i.e.
// fibonacci). It calls itself, which means
// this mtx.lock() gets called multiple times.
// If this is a plain mutex, it will deadlock
// because you've already locked it- if it
// is a recursive mutex you'll be just fine.
mtx.lock();

int ret = (0 == i || 1 == i) ? 1 : fibonacci(i-1) + fibonacci(i - 2);

mtx.unlock();

return ret;
}


/**
 * This is a simple newThread launch function.
 */
void newThread(int threadId)
{
// This mutex is just used to do printing.
static boost::mutex mtx;

int fib = fibonacci(threadId);

// Simply guard the print statement so it
// won't become garbled.
mtx.lock();
std::cout << "fib(" << threadId << ") = " << fib << std::endl;
mtx.unlock();
}


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();
}

No comments:

Post a Comment