It's not possible to utilize boosts condition variables without using locks. Were it not for that requirement, I would much prefer just to use mutexes and never to use locks. But I need to use condition variables, so use locks I must. A lock is a variable which is instantiated as an object of type boost::lock. Well, there really isn't a boost class named boost::lock. Rather, there are several types of locks. The several types of locks have different names rather than all having the same name with different options. We will be looking at locks of type boost::lock_guard and of type boost::unique_lock. Locks do not replace mutexes. Rather, locks enhance the function of mutexes. In particular, locks include a pointer to a mutex, and locks include member methods to help manage the mutex to which they point. The simplest type of lock is of type boost::lock_guard. It has no options, and there is only one way to use it. This example will use a lock_guard to serialize two threads rather than using a mutex to serialize two threads. |
Scope is hugely important to the way locks work. Indeed, one of the primary motivations for developing locks was to provide a way to be sure that mutexes are released, even if an exception is thrown after locking a mutex and before unlocking the mutex. To that end, mutexes continue to require a scope that lasts until the threads are completed, even when mutexes are used along with locks. But the locks themselves have a scope that is very brief. Locks are expected to go in and out of scope many times and to stay in scope very briefly. Which is to say that much or all of the processing performed by locks is performed by their constructors and destructors. |
#include "stdafx.h" #include <iostream> #include <boost/thread.hpp> void funct1(); void funct2(); boost::mutex zzzz; int main() // sample program using lock_guard { boost::thread xxxx(funct1); boost::thread yyyy(funct2); xxxx.join(); yyyy.join(); return 0; } void funct1() { { // artificially create a scope to contain the lock // the constructor for the wwww object // locks the mutex called zzzz boost::lock_guard<boost::mutex> wwww(zzzz); for (int i = 0; i < 50; i++) std::cout << '?'; std::cout << std::endl; } // the lock called wwww goes out of scope at //this point and the destructor unlocks the mutex zzzz } void funct2() { { // artificially create a scope to contain the lock // the constructor for the vvvv object // locks the mutex called zzzz boost::lock_guard<boost::mutex> vvvv(zzzz); for (int i = 0; i < 50; i++) std::cout << '!'; std::cout << std::endl; } // the lock called vvvv goes out of scope at // this point and the destructor unlocks the mutex zzzz } |
|
#include "stdafx.h" #include <iostream> #include <boost/thread.hpp> void funct1(); void funct2(); boost::mutex zzzz; int main() // sample program using unique_lock instead of lock_guard { boost::thread xxxx(funct1); boost::thread yyyy(funct2); xxxx.join(); yyyy.join(); return 0; } void funct1() { { // artificially create a scope to contain the lock // the constructor for the wwww object // locks the mutex called zzzz boost::unique_lock<boost::mutex> wwww(zzzz); for (int i = 0; i < 50; i++) std::cout << '?'; std::cout << std::endl; } // the lock called wwww goes out of scope at //this point and the destructor unlocks the mutex zzzz } void funct2() { { // artificially create a scope to contain the lock // the constructor for the vvvv object // locks the mutex called zzzz boost::unique_lock<boost::mutex> vvvv(zzzz); for (int i = 0; i < 50; i++) std::cout << '!'; std::cout << std::endl; } // the lock called vvvv goes out of scope at // this point and the destructor unlocks the mutex zzzz } |
|
This page last edited on 26 Mar 2016.