Multithreaded C++: Part 2: Boost Threads

If pthreads represent the assembly language of multithreading programming, then boost::threads represent the C of multithreaded programming.

Boost threads introduce some handy code saving features for the creation of threads, which is nice, but not as important as the RAII techniques they put to use for mutex management. In this case an example is worth a thousand words. Here is the same code we wrote in for pthreads rewritten for boost::threads:

class threaded_class
{
public:
    threaded_class()
        : m_stoprequested(false)
    {
    }

    ~threaded_class()
    {
    }

    // Create the thread and start work
    void go()
    {
        assert(!m_thread);
        m_thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&threaded_class::do_work, this)));
    }

    void stop() // Note 1
    {
        assert(m_thread);
        m_stoprequested = true;
        m_thread->join();
    }

    int get_fibonacci_value(int which)
    {
        boost::mutex::scoped_lock l(m_mutex); //Note 2
        return m_fibonacci_values.get(which);
    }

private:
    volatile bool m_stoprequested;
    boost::shared_ptr<boost::thread> m_thread;
    boost::mutex m_mutex;
   
    std::vector<int> m_fibonacci_values;

    int fibonacci_number(int num)
    {
        switch(num)
        {
            case 0:
            case 1:
                return 1;
            default:
                return fib(num-2) + fib(num-1);
        };
    }    

    // Compute and save fibonacci numbers as fast as possible
    void do_work()
    {
        int iteration = 0;
        while (!m_stoprequested)
        {
            int value = fibonacci_number(iteration);
            boost::mutex::scoped_lock l(m_mutex);
            m_fibonacci_values.push_back(value);
        }
    }                    
};

From the last pthreads example to this example our entire implementation, including comments and white space, decreased from 78 lines of code to 64. In this simple case, that was an 18% savings. Smaller, easier to read code is less error prone and easier to maintain (and therefore cheaper to write and maintain). We'll see in future articles that we can keep going with this, making the code even more succinct.

Notes regarding this version:

Note 1
In this version we still have the problem we had in the pthreads version. If we forget to call "stop" on this object we are going to at least leak thread resources and probably cause a crash.
Note 2
The boost::mutex::scoped_lock class provides a handy RAII way of managing mutex locks. In our pthread only version we were very much at risk of forgetting to unlock a mutex we had locked, causing a difficult to debug deadlock.

In this case, the length of the mutex is governed by the lifetime of the scoped_lock object. Because the scoped_lock will be destroyed as soon as it goes out of scope we know we are guaranteed to never forget to unlock the mutex.

Part 1

Comments

Hi Jason,

Nice post.
I came to your blog through google. Can you guide me to a simple example for a threaded code in C++ ?

Reshmi

Reshmi, the simplest meaningful example that I was able to come up with was the one I wrote for the pthreads article I have on this page: http://blog.emptycrate.com/node/270.

However, I don't recommend using pthreads in C++. It has several disadvantages, mostly in that it was written to work with C more than C++, so you must use a static or global function to launch your C++ code. The pthreads article linked above describes that in more detail.

I strongly recommend using a higher level abstraction such as boost::threads as this article describes or building or using some even higher level abstraction.

Can you please include the header files? Saves time hunting on google. :-)

#include <boost/bind.hpp>
#include <boost/thread/thread.pp>
#include <boost/thread/mutex.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

That should pretty much do it.

I know that this is a very old thread. However, this was a great help. I just wish it was more easy to follow. I'm a beginner from the Windows side of the world. So put up this simple guide for those who are beginners like me. For Visual Studio users, here's a more complete example (But not the safest I think). Make sure you add the Boost Lib, and the Includes Folder.

Using Visual Studio 2010:

  1. Go to File -> New -> Project. Choose a name for you project.
  2. On the left side at the Installed Templates Choose Visual C++, then Win32. Then click on the Win32 Console Application. Click Next.
  3. The Win32 Console App Wizard will open. Click next on the Welcome Page.
  4. Choose Console Application as the Application Type.
  5. Choose Empty Project for Additional Options.
  6. Uncheck Precompiled Header, ATL and MFC.
  7. Click Finish.
  8. At the Solutions Explorer, right click on the project, and then Click Properties.
  9. In the Configuration Properties, go to VC++ Directories.
  10. In the Configuration Drop Down choose All Configurations.
  11. In the Include Directories, add the Root of your Boost.
  12. In the Library Directories, add the lib folder of your Boost. Then confirm the changes.
  13. Press Ok to Confirm.
  14. Right Click on the Project Again and Add Class.
  15. Choose the C++ Class File. And press Ok to Confirm.
  16. Name the Class CThreadedFib. The .h File and .cpp file will be populated as you type.
  17. Make sure you make its Access in to Public, and Virtual Destructor and Inline are Unchecked.
  18. Copy the code below to the corresponding auto generated files on your project.
  19. Right Click again on your project from the solutions explorer, and Add New Item.
  20. Choose C++ File (.cpp) and name it main.cpp.
  21. Copy from the main.cpp code listing below to the newly created file.
  22. Build.
  23. The program should try to get the Fib(60). It will sleep if the worker thread isn't done yet.

There is a part of the code from the main.cpp that you can uncomment which will allow the program to stop the worker thread before it completes its task. It then stops gracefully.

ThreadedFib.h - The Class Header file

#pragma once

#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

#include "boost/date_time/posix_time/posix_time.hpp"

class CThreadedFib
{
public:
        // constructor
        CThreadedFib(void);
       
        // destructor
        ~CThreadedFib(void);
       
        // Create the thread and start work
        void Go();
       
        // Stops the thread
        void stop();
       
        // returns that value of the vector at the nth element - element
        unsigned long get_FibonacciAt(int element);
       
        // returns the current vector size
        int get_VectorSize();
       
        // returns if the current worker is busy
        bool get_isBusy();
       
        // sets the maximum value to check
        void set_FibSteps(int fibSteps);
       
        boost::posix_time::time_duration CThreadedFib::get_Duration();
       
private:
        boost::posix_time::ptime m_TimeStart;
        boost::posix_time::ptime m_TimeStop;
       
       
        // is the worker busy? stores this variable.
        bool m_Busy;
       
        // private field for the maximum value to check
        int m_FibSteps;
       
        // true if a stop was requested, false otherwise
        volatile bool m_stoprequested;
       
        // thread pointer
        boost::shared_ptr<boost::thread> m_thread;
       
        // mutex - locks following variables to current thread
        boost::mutex m_mutex;
       
        // the vector which stores the fib sequence
        std::vector<unsigned long> m_fibonacci_values;
       
        // the basic fibonacci function - using unsigned long for max efficiency
        unsigned long fibonacci_number(unsigned long num);
       
        // Compute and save fibonacci numbers as fast as possible
        void do_work();
};

ThreadedFib.cpp - The Class Header file

#include "ThreadedFib.h"

#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

// constructor implementation
CThreadedFib::CThreadedFib(void)
{
        this->m_Busy = false;
        this->m_FibSteps = 95;
        this->m_stoprequested = false;
}

// destructor implementation
CThreadedFib::~CThreadedFib(void)
{
        boost::mutex::scoped_lock l(this->m_mutex);
        if (this->m_Busy == true)
        {
                this->stop();
        }
}

bool CThreadedFib::get_isBusy()
{
        return this->m_Busy;
}

// starts the worker thread.
void CThreadedFib::Go()
{
        if (!this->m_Busy)
        {
                this->m_TimeStart = boost::posix_time::second_clock::local_time();
                this->m_Busy = true;
                this->m_stoprequested = false;
                assert(!this->m_thread);
                this->m_thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&CThreadedFib::do_work, this)));
        }
}

// returns the current size of the vector
int CThreadedFib::get_VectorSize()
{
        boost::mutex::scoped_lock l(this->m_mutex);
        return this->m_fibonacci_values.size();
}

// stops the thread worker if it's running
void CThreadedFib::stop() // Note 1
{
        if (this->m_Busy == true)
        {
                assert(this->m_thread);
                this->m_stoprequested = true;
                this->m_thread->join();
                this->m_Busy = false;
        }
}

// returns the current value of the
unsigned long CThreadedFib::get_FibonacciAt(int element)
{
        boost::mutex::scoped_lock l(this->m_mutex); //Note 2
        return this->m_fibonacci_values.at(element);
}

unsigned long CThreadedFib::fibonacci_number(unsigned long num)
{
        switch(num)
        {
                case 0:
                        return 0;
                case 1:
                        return 1;
                default:
                        return this->fibonacci_number(num-2) + this->fibonacci_number(num - 1);
        };
}  

// Compute and save fibonacci numbers as fast as possible
void CThreadedFib::do_work()
{
        int iteration = 0;
        while (!this->m_stoprequested &&  iteration < this->m_FibSteps)
        {
                int value = this->fibonacci_number(++iteration);
                boost::mutex::scoped_lock l(this->m_mutex);
                this->m_fibonacci_values.push_back(value);
        }

        boost::mutex::scoped_lock l(this->m_mutex);
        this->m_Busy = false;
        this->m_stoprequested = false;
        this->m_TimeStop = boost::posix_time::second_clock::local_time();      
}

void CThreadedFib::set_FibSteps(int fibSteps)
{
        boost::mutex::scoped_lock l(this->m_mutex);
        this->m_FibSteps = fibSteps;
}

boost::posix_time::time_duration CThreadedFib::get_Duration()
{
        return this->m_TimeStop - this->m_TimeStart;
}

main.cpp - The Class Header file

#include <iostream>
#include <stdio.h>
#include <boost/algorithm/string.hpp>
#include <Windows.h>

#include "ThreadedFib.h"

#include "boost/date_time/posix_time/posix_time.hpp"

using namespace boost::posix_time;
using namespace std;
using namespace boost;

string printTime()
{
        ptime now = second_clock::local_time();
        return to_simple_string(now);
}

int main()
{
       
        // maximum fibonacci number to get
        int max = 60;

        // the current size of the vector element holds the fib sequence
        int size;

        // the value of the nth element of the vector
        unsigned long i;

        // creates the fib worker
        cout << printTime() << ": Creating the fib worker." << std::endl;
        CThreadedFib fib;

        // initiallizes the new max value (default to 10 - check constructor)
        fib.set_FibSteps(max);

        // Starts the fib worker
        cout << printTime() << ": Starting the fib worker." << std::endl;
        fib.Go();
       
        // to give the worker a jump start.
        cout << printTime() << ": Sleeping for 2 seconds." << std::endl;
        Sleep(2000);

        // Loops and checks if we have reached the max value to get the fib num.
        while (fib.get_VectorSize() <= max && fib.get_isBusy())
        {
                // make sure that the vector size > 0, else there'd be no content
                if (fib.get_VectorSize() > 0)
                {
                        // This part you can turn on if you want to stop before
                        // the completion of the entire loop to the fib of max.
                        //if (fib.get_VectorSize() > 35) {
                        //      fib.stop();
                        //}

                        // get the size of the vector
                        size = fib.get_VectorSize();

                        // set i as the last value calculated
                        i = fib.get_FibonacciAt(size-1);

                        // show resluts
                        cout << printTime() << ": The value of fib @ " << size << " is " << i << std::endl;

                        // sleep again.
                        cout << printTime() << ": Sleeping for another 2 seconds." << std::endl;
                        Sleep(2000);
                }
        }
       
        cout << printTime() << ": Stopping fib worker." << std::endl;
        fib.stop();

        cout << printTime() << ": Sleeping for 2 seconds to stop." << std::endl;
        Sleep(2000);

        cout << printTime() << ": Geting the number of iterations." << std::endl;
        size = fib.get_VectorSize();
        i = fib.get_FibonacciAt(size-1);
        cout << printTime() << ": The value of fib(" << size << ") is " << i << std::endl;
        cout << printTime() << ": Real solving time duration was " << to_simple_string(fib.get_Duration()) << std::endl;

        cout << "Press any key to continue!" << std::endl;
        getchar();

        return 0;
}

It might be just let night... or the coming Haloween...
Isn't the idea to increment iteration for this example to work right?

void do_work()
{
int iteration = 0;
while (!m_stoprequested)
{
int value = fibonacci_number(iteration);
boost::mutex::scoped_lock l(m_mutex);
m_fibonacci_values.push_back(value);
}
}

Thanks,

Gil

This article has been up for months... 6000+ reads. You are the first person to notice that bug. I wish I had some kind of a prize to give you.

void do_work()
{
  int iteration = 0;
  while (!m_stoprequested)
  {
    int value = fibonacci_number(iteration);
    boost::mutex::scoped_lock l(m_mutex);
    m_fibonacci_values.push_back(value);
    ++iteration; //This should work better!
  }
}

-Jason

Then fix the listing please. I've spent 10 min trying to find out if I was not seeing the bug, checking if you were passing by reference and incrementing outside, or if the variable was global, no idea.

I don't get it why you don't fix the listing.

In any case, thanks a lot for the example. It has helped me a lot.

Julian

get_fibonacci_value(int) method is not used.

fib(int) is not declared.

is code complete?

thanks!

maybe fibonacci_number is a recursive method so its name should be fib()
then get_fibonacci_value should be the public method to access this "service"

Correct, fib() is a bug, it should be calling fibonacci_number(). Also, this is a CLASS not a complete program. You would use get_fibonacci_value as an accessor into the threaded calculation of fibonacci numbers.

hi,
i used your concept using mutexes.But the thing is that my threads continously need to be running and should be stopped until and unless the program exist.So tioll that time i can not call stop function.So in order to avoid crashing wat should i do???

I would put to use RAII management of my thread: (this is covered in Multithreaded C++: Part 3: RAII And Threads)

I would update the destructor of this class to automatically shutdown the thread when it is called:

 ~threaded_class()
    {
      //Warning this stop call will fail if stop had been called previously,
      //see Multithreaded C++: Part 3: RAII And Threads for a more robust
      //example
      stop();
    }

Then I would place the object at the appropriate scope so that its lifetime was what I needed it to be.

int main()
{
  threaded_class fibcalc;

  //Do stuff
  doSomethingWithFibCalc(fibcalc);

  //When main() exits fibcalc is popped from the stack, its destructor is called and the
  //Thread is automatically stopped and joined.
}

I feel compelled to point out that this example is mostly academic. It's a fun way to illustrate the use of boost threads and mutexes, but it's a very inefficient way of calculating the Fibonacci sequence. A method utilising a cache or even calculating the sequence statically at compile time is a much better option.

fib(0) should return 0, not 1.

I always thought it started at 1, not 0.

the fibo-numbers are a 2d space depending on the first 2 numbers, so what.

I downloaded this and attempted to compile. These are the changes I found necessary to make it compile and work properly:

--return m_fibonacci_values.get(which);
should be:
--return m_fibonacci_values.at(which);

--int value = fibonacci_number(iteration);
should be:
--int value = fibonacci_number(iteration++);

--return fib(num-2) + fib(num-1);
should be:
--return fibonacci_number(num-2) + fibonacci_number(num-1);

So useful - thanks so much.

That volatile in your example is neither necessary nor sufficient. volatile does NOT replace proper thread synchronization mechanisms, i.e. mutexes, and if you use them, volatile isn't necessary anyway.
Using volatile in that way may actually do what you think it does on __some__ platforms, but it is certainly NOT portable.

I thought the same thing! being quite surprised surprised to see the 'volatile' keyword there. Thanks for confirming my doubts ;)

I did some homework after reading your comments. The best article I can find about the volatile subject is from Herb Sutter.

You are correct that volatile makes no guarantees that it will work in this situation, and the only truly safe way to implement the "bool continue" check is with mutex locks.

However, if you wanted to implement the check without a lock, you must use a special variable type that is not cached, or you risk the variable never being re-read by the running thread (a case that I have experienced). Using volatile for this case has proven to be successful on both x86 and ARM on GCC/Linux.

I'd love it if someone could give clear examples of where this example does not work.

I've also used volatile for threading in this type of scenario.
It IS safe, for example bool on x86, since the instruction to set/read a bool are atomic on x86.
It wouldn't be safe, for instance on an Alpha which uses multiple instructions to set or clear smaller variables (at least it did on the 21264).
This really becomes important depending on what you're using it for.
If, for example, you were sharing an int between multiple threads, and adding number to it across multiple threads, then it could be very dangerous - for instance a 64-bit int on a 32-bit Intel would be very bad because operations on that int wouldn't be atomic - and you could totally mangle the value of the int if a context switch happened in between the instructions.
However, if you're simply using the bool as a shutdown flag, as you are here, then this code should be quite safe on most platforms. It really comes down to how purist you want to be, and whether performance is important - in this case it feels like overkill to me to wrap that flag in a mutex - perhaps using an event would be a better solution.
I realise that traditionally threading is solved with locking, but it's a very blunt hammer and sometimes you can end up with 'multi-threaded' code that can barely use 2 CPUs, let alone 4.
I've spent some time in the last couple of years learning to write lockless code where possible, as it scales a lot better. It's a bit more of a strain on your brain, but it's doable! The new atomic operations in C++11 will help a lot.
Having said all of that, you should at least have a comment in your code pointing out the 'non-portable' construct - I think it's ok to use it, but important that people can easily understand the limitation.

Many thanks for your practical example, which has also helped me a lot. Here is from my side, what I compiled/run, from your code:

class threaded_class
{
        private:
        volatile bool m_stoprequested;
        std::vector<int> m_fibonacci_values;
        boost::mutex m_mutex;
        boost::thread m_thread;
        int nbFibSteps;
        int fib(int num)
        {
                switch(num)
                {
                        case 0: return 0; case 1: return 1;
                        default:
                        return fib(num-2) + fib(num-1);
                };
        }
       
        void do_work()
        {
                int iteration = 0;
                while (!m_stoprequested &&  iteration<nbFibSteps)
                {
                        int value = fib(++iteration);
                        boost::mutex::scoped_lock l(mutex);
                        m_fibonacci_values.push_back(value);
                }
        }

        public:
        threaded_class()
        : m_stoprequested(false),
nbFibSteps(10),
        m_thread(boost::bind(&threaded_class::do_work, this)) //Note 2 
        {}
        ~threaded_class()
        {
        m_stoprequested = true;
        m_thread.join(); //Note 2
}      

        int get_fibonacci_value(int _idx)
        {
        boost::mutex::scoped_lock lock(m_mutex);
        return m_fibonacci_values[_idx];
        }
};
       
int main()
{
        threaded_class fibcalc;
        fibcalc.get_fibonacci_value(4);
        return 0;
}

1. I get that the thread is constructed and launches do_work in the constructor. I nevertheless found it perhaps necessary to add the “nbFibSteps” variable as a member of the class, such that after it is set up in the constructor (to 10) the "while" condition in do_work becomes as follows:

while (!m_stoprequested &&  iteration<nbFibSteps)

(so that the loop stops when a 10-element vector is built). Any thought?

2. I have a question, looking at the previously written "while" condition

while (!m_stoprequested)

as such and according to the main I wrote (a very basic example), isn't it going to go into a infinite loopuntil the main exits? Could anyone confirm/explain?

3. Lastly, this my code simply ends-up with a crash, where the m_mutex lock is involved. Any thought about what I did wrong?

Regards.

This is a very good, concise tutorial...thank you for posting. Although I don't have problems getting threading to work, I'm trying to encapsulate the do_work() method within a pImpl idiom child class. I can't for the life of me get the boost::bind to successfully combine when I try to perform the bind to do_work() residing within a pImpl class. If you have a moment, and the interest, I would be very interested in seeing this same example, but with the implementation definitions found within a pImpl class. Thank you very much!