/**
* In one of my last posts, I started looking
* at recursive_mutex as a "clean" way to handle
* recursive functions and locking. What I didn't
* realize is how "frowned upon" they are- Even
* the bad features have their appropriate uses.
* So why so much hate for recursive_mutex?
*
* The first con to using a recursive_mutex is
* the cost involved in calculating the count.
* Every time you lock there is a count that is
* increased on the mutex. The same thread increments
* this use count every time it locks. However,
* to fully unlock it also needs to call
* unlock() the same number of times.
*
* The second con of using a recursive_mutex
* is that it doesn't work well with scoped_lock,
* which is a nice convenience class provided
* by boost (remember the RAII implementation).
*
* The third reason (and the one I don't fully
* understand) is that unlocking the resource
* is sometimes not unlocking the resource. I
* don't want to reference where I read this-
* Mainly because it's from a blog that reads
* more like a rant.
*
* Considering the three reasons, I started
* playing around with some new implementations.
* I am most concerned about the speed of using
* the recursive mutex and second most concerned
* about the readability. Therefore the prior
* blogpost was re-written to use regular
* vanilla mutexes.
*/
// This header is needed to get the awesome
// scoped_lock provided by boost.
#include <boost/thread/mutex.hpp>
// This is needed to use the conditions.
#include <boost/thread/condition.hpp>
#include <boost/thread.hpp>
#include <iostream>
// We have one mutex for output.
static boost::mutex mtx;
/**
* Notice that the following two methods are
* exactly the same as before, with the exception
* that they have the underscore afterwords.
* I hope that this would be a clue to readers
* that this function is not to be called directly.
* Normally you would make this innaccessable to
* other developers by making it private.
*/
template <typename T>
void print_(T const& t)
{
std::cout << t;
}
/**
* These methods are exact copies of the prior
* blogpost with the exception that they do not
* lock at all. This is recursive behavior- so
* locking would cause deadlocks.
*/
template <typename T, typename... Parameters>
void print_(T const& t1, Parameters... parms)
{
std::cout << t1;
if (sizeof...(Parameters))
{
print_(parms...);
}
}
/**
* Here is where the implementation design comes
* in. Our public function that is non-recursive
* does the locking! It then simply calls our
* private recursive functions. This eliminates
* the need for a recursive lock.
*/
template <typename T>
void print(T const& t)
{
boost::mutex::scoped_lock lock(mtx);
print_(t);
}
/**
* Same comment as above.
*/
template <typename T, typename... Parameters>
void print(T const& t1, Parameters... parms)
{
boost::mutex::scoped_lock lock(mtx);
print_(t1, parms...);
}
/**
* For right now, ignore the condition parameter. I
* haven't quite figured out how that all works
* yet.
*/
void runThread(int id, boost::shared_ptr<boost::condition> cond)
{
for(int i=0; i<5; ++i)
{
print("Thread #", id, " (iteration=", i, ")\n");
}
}
int main(int argc, char** argv)
{
boost::shared_ptr<boost::condition> cond(new boost::condition());
boost::thread t1(runThread, 1, cond);
boost::thread t2(runThread, 2, cond);
boost::thread t3(runThread, 3, cond);
boost::thread t4(runThread, 4, cond);
t1.join();
t2.join();
t3.join();
t4.join();
}
/**
* In conclusion, developers are a very passionate bunch.
* I understand and get it- I have the same vehement hatred
* for auto_ptr (I want to rant about it but I won't).
* I think when I see one person speak up about how bad
* something is I try to push the criticism aside. When
* an entire group of developers shun something I take
* notice; I won't be using recursive_mutex's in my code
* anytime soon!
*/
Saturday, May 11, 2013
Update on recursive_mutex.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment