Boost libraries (Boost.Thread) provide an easy implementation for multi-threading applications in C++.
Code is portable on different OS platforms. Three basic code examples are discussed below for a kick start on use of these libraries.
Last example also shows the use of mutex.
On Linux, it uses pthreads underlying. So it can be thought of pthreads wrapped in C++ style objects. BOOST library provides different ways to use locks also.
Here is the official link:-
http://www.boost.org/doc/libs/1_49_0/doc/html/thread.html
Example-1 : Basic Multi-threading
This simple example spawns two threads. Callback function for each thread is invoked.
void readerApi()
{
for (int i=0; i < 10; i++) {
usleep(400);
std::cout << "readerApi: " << i
<< std::endl;
}
}
void writerApi()
{
for (int i=0; i < 10; i++) {
std::cout << "writerApi: " << i
<< std::endl;
usleep(400);
}
}
int main()
{
boost::thread readerThread(readerApi);
boost::thread writerThread(writerApi);
readerThread.join();
writerThread.join();
}
Compile and output:
$ ./b1
writerApi: 0
readerApi: 0
writerApi: 1
readerApi: 1
writerApi: 2
readerApi: 2
writerApi: 3
writerApi: 4
readerApi: 3
writerApi: 5
readerApi: 4
writerApi: 6
readerApi: 5
writerApi: 7
readerApi: 6
writerApi: 8
readerApi: 7
writerApi: 9
readerApi: 8
readerApi: 9
Example-2 : Thread Callbacks with parameters
In this example a parameter, pointer to shared variable is passed to the callback.
Writer callback modifies the variable at regular intervals.
Reader callback dumps the value, writer callback modifies the value.
void readerApi(int* readVar)
{
for (int i=0; i < 10; i++) {
usleep(400);
std::cout << "readerApi: " << *readVar
<< std::endl;
}
}
void writerApi(int* writeVar)
{
for (int i=0; i < 10; i++) {
std::cout << "writerApi: " << *writeVar
<< std::endl;
usleep(400);
*writeVar = (*writeVar)++;
}
}
int main()
{
int variable = 100;
boost::thread readerThread(readerApi, &variable);
boost::thread writerThread(writerApi, &variable);
readerThread.join();
writerThread.join();
}
Compile and output:
$ ./b2
writerApi: 100
readerApi: 100
writerApi: 101
readerApi: 101
writerApi: 102
readerApi: 102
writerApi: 103
readerApi: 103
writerApi: 104
readerApi: 104
writerApi: 105
readerApi: 105
writerApi: 106
readerApi: 106
writerApi: 107
readerApi: 107
writerApi: 108
readerApi: 108
writerApi: 109
readerApi: 109
Example-3 : Classes for callback. Usage of Mutexes
Instead of using callback functions, we use an object.
Object should be ‘callable‘, means have operator () overloaded within the class.
Writer takes a lock before modifying the shared variable. And then update global variable with this variable.
Reader accesses the global variable for its use.
int globalVariable;
class Reader
{
public:
Reader(int waitTime) { _waitTime = waitTime;}
void operator() () {
for (int i=0; i < 10; i++) {
std::cout << "Reader Api: " << globalVariable << std::endl;
usleep(_waitTime);
}
return;
}
private:
int _waitTime;
};
class Writer
{
public:
Writer(int variable, int waitTime)
{
_writerVariable = variable;
_waitTime = waitTime;
}
void operator () () {
for (int i=0; i < 10; i++) {
usleep(_waitTime);
// Take lock and modify the global variable
boost::mutex::scoped_lock lock(_writerMutex);
globalVariable = _writerVariable;
_writerVariable++;
// since we have used scoped lock,
// it automatically unlocks on going out of scope
}
}
private:
int _writerVariable;
int _waitTime;
static boost::mutex _writerMutex;
};
boost::mutex
Writer::_writerMutex;
int main()
{
Reader reads(100);
Writer writes1(100, 200);
Writer writes2(200, 200);
boost::thread readerThread(reads);
boost::thread writerThread1(writes1);
usleep(100);
boost::thread writerThread2(writes2);
readerThread.join();
writerThread1.join();
writerThread2.join();
}
Compile and output: (Output will be different in different runs as the order of updation may vary)
$ ./b3
Reader Api: 0
Reader Api: 200
Reader Api: 103
Reader Api: 104
Reader Api: 106
Reader Api: 107
Reader Api: 109
Reader Api: 209
Reader Api: 209
Reader Api: 209
Good Article. This article can serve as a primer for anyone looking to do multi-threading work with Boost.Thread library, which I find the simplest library to multi-threaded library to use. Very useful !!!
Awesome Post!!!
Wonder if in the example 3, Reader class, there was some intent to use _waitTime member?
Also there, I am not quite sure that private _writerMutex could be initialized just like that…
Intent in using _waitTime is to delay the read, write a bit, so that the example becomes clear in terms of steps performed.
Regarding mutex, I do not see any issues, please point out specifically, I will humbly correct it.
In somewhat similar wake – why do we need this in main():
int variable = 100;
?
I was wrong about private static boost::mutex _writerMutex; initialization – it is allowed.
Good you agree for mutex. Variable “variable” was unused. I have corrected it and used _waitTime also. Thanks for pointing out.
Hi Ashish,
In example 1,when printing on console,context switch might happen resulting in haphazard view on console . We can do following to overcome this :-
1)Just use a simple mutex within each thread. The mutex is shared by all threads.
2)Send all the output to a single thread that does nothing but the logging.
3) Send all the output to a separate logging application.
Agreed. The idea of this post is to present a primer material on BOOST multi-threading. So I have kept it simple.
“Object should be ‘callable‘, means have operator () overloaded within the class.”
This is also known as function object(functor) .
Also to achieve functionality of callbacks,boost::future and boost::promises are handy stuff.
void callfunc(future f) {
std::cout << "Future is ready with value = " << f.get() << "\n";
}
void f9() {
promise pi;
future f(pi);
boost::callback_reference cb_ref1 = f.add_callback(boost::bind(callfunc, f));
pi.set(33); // my callback will print “Future is ready” now
}
Wow Excellent blog!
Wow Excellent blog!
[…] http://ashishgrover.com/boost-multi-threadingfor-c/ […]
Hi Ashish,
Can you please suggest a Linux OS which I can use to learn C++. I am currently using Maveric OSX. I am running into issues while trying to integrate BOOST libraries.
Regards,
Avinash
You can use Ubuntu.
Thanks much for the post! I have a simple question: why _writerMutex is defined as static variable?
Multiple writers (or objects of Writer class) need to be synchronized. Having static ensures a common mutex.
hello
i would thanks for this objective tutorial that make a lot of thing easy for me about thread’s techniques.
i have a simple issue, that the usleep function doesn’t work for me.
the complier tell me that this function is undefined.
what shall i do ?
thanks again
I’ve been looking for this. Thank you
@mohamed
To resolve usleep() related error, use following:
1. Add #include
2. boost::this_thread::sleep(boost::posix_time::milliseconds(100)); //thread will sleep for 100ms.
Regards,
Swanand
example 2 gives the o/p like as below: Let me know why boost thread is updating the variable ?
writerApi: 100
readerApi: 100
writerApi: 100
readerApi: 100
writerApi: 100
readerApi: 100
writerApi: 100
……………….
k got it..
update the code
*writeVar = *writeVar + 1;
Good tutorial. However I’d like to point out (correct me if I’m wrong) that statements such as
x=x++;
are undefined.
So
*writeVar = (*writeVar)++;
seems like a… Strange choice, considering that (*wirteVar)++ would achieve the desired result.
Also, I compiled your code with g++ and indeed, leaving the
*writeVar = (*writeVar)++;
line results in and output that is always 100 (since apprently this depends on the compiler).
I think you should correct that or correct me.
Cheers