Jerry's Tutorials: Turning Functions into Threads, 1 of 3

Jerry's Tutorials: Turning Functions into Threads, 1 of 3


My current C++ compiler is Microsoft's Visual Studio Version 10.  This compiler is old enough that it does not support C++11.  C++11 supports threads natively, but the earlier version of C++ that is supported by my compiler does not support threads natively.  Therefore, I am using boost for thread support.

I believe that the support for threads in C++11 is fairly compatible with the support for threads in boost::thread.  Therefore, I'm hoping that if ever I upgrade to a compiler that supports C++11, the only thing I would have to do would be to replace the include statements for boost::thread with include statements for std::thread.

In order to use boost, you have to download it from http://www.boost.org/users/download/.  The download process is very easy, but the installation process is not so easy.  To use boost you will need both the header files to be included in your program at compile time and some binary files to be included in your program at link time.  It is much easier to install the header files than it is to install the binary files.

All you have to do for the header files is to point your compiler to wherever you downloaded the files.

Preparing the binary files for link time is a much more complicated process than is installing the header files, and the documentation is rather challenging.  There are several different ways to prepare the binary files, which is one of the reasons the documentation is so challenging.  It's not always very clear which of the several ways to prepare the binary files is the best one to use.

I found that I had to compile and link many thousands of modules and the process took several hours to run.  There may have been some pre-built executables for Windows that I could have simply pointed to, but if so then I couldn't find them.  Also, you can compile and link either 32 bit executables or 64 bit executables, or both.  Without quite knowing what I was doing, I ended up compiling and linking only the 64 bit executables and I didn't want to fight through the details and the time of getting both the 32 bit and 64 bit versions working.  So if I need to use boost in a program, I have to make my program a 64 bit program even if it could get by as a 32 bit program.


// This code contains errors. Do not run it until we have
// eliminated all the errors.

#include "stdafx.h"
#include <iostream>
#include <boost/thread.hpp>

void funct1();
void funct2();

int main()
{	
    boost::thread xxxx(funct1);
    boost::thread yyyy(funct2);
    return 0;
}

void funct1()
{
    for (int i = 0; i < 50; i++) std::cout << '?';
    std::cout << std::endl;
}

void funct2()
{
    for (int i = 0; i < 50; i++) std::cout << '!';
    std::cout << std::endl;
}
  • The first and most basic thing you have to do to turn your functions into threads is to include the header for the thread library, namely thread.hpp.  In my case, I have pointed the compiler to the folder where my boost download is stored, and the headers for the thread class are in a subfolder called boost within my download area.  You will have to understand how to point your compiler to the boost download area and you will have to understand where the thread.hpp header file is stored within the boost download area.  Your mileage may vary, and I will leave this as an exercise for the student for now since not everybody reading this will be using Visual Studio as I am using.
  • The second and equally important thing you have to do is to replace your function calls with instantiations of objects of class boost::thread, and you have to pass the names of your functions as arguments to the constructor for this class.  That's just a fancy way of saying that you have to create variables of type boost::thread, and you have to list the name of the function to be called as a thread in parentheses after the name of the thread variable.
    • For the purposes of my example, I have named the thread objects with the nonsensical names xxxx and yyyy.  Almost all example code you will find on the Internet will give these variables more meaningful names, and any code you write for yourself should give these variables meaningful names.  For example, you might call the threads thread1 and thread2 rather than xxxx and yyyy.  But for my tutorial, I prefer to use nonsensical names to emphasize that these are just variables that can be named anything at all, and that there are no semantics associated with your choice of names for the thread objects.  Also, I want to emphasize that there is no connection between the name of the thread objects and the name of the functions that will be invoked by the thread objects.  That is, there is no connection between the name xxxx for the first thread object and the function name funct1 that will be invoked by the first thread object, and there is no connection between the name yyyy for the second thread object and the function name funct2 that will be invoked by the second thread object.
  • The third and equally important thing you have to do is to point your linker to the boost executable library.  Again, I will leave this as an exercise for the student for now because not everybody reading this will be using Visual Studio.

  • We make note of the fact that the functions in this example do not take arguments.  It is possible to pass arguments to functions that are invoked as a thread, but that is a more complicated subject that we will defer to later in the tutorial.  For the time being, we simply observe that as arguments to the constructor for the thread class, function names are not followed by parentheses as they are when functions are invoked directly in C++.  That is, your code does not say boost::thread xxxx(funct1()); Instead, it simply says boost::thread xxxx(funct1);
  • It is very common in the boost library that the instantiation of an object also initializes the object.  To tell you the truth, most of the time I prefer not to write my code in that fashion and I've had to get used to doing things a little differently than what I usually prefer.  For example, I would usually prefer to write my code as something like
    boost::thread xxxx;  // define a thread object
    
    followed somewhat later in code by something like
    xxxx.create_thread(funct1);  // launch funct1 as a thread
    
    I think the latter way of writing the code provides vastly more clarity.  But when boost doesn't work that way, then I have to write my code in the manner which boost supports.
  • The style of coding that boost is using to instantiate threads is called RAII (Resource Acquisition Is Initialization.  Even though I don't like RAII very much, RAII has some significant advantages.  Proponents suggest that RAII actually provides more clarity to code, not less.  I will have more to say about RAII when we get deeper into the details of boost's condition variables.
  • The code to the left will compile without error, and and will sort of run, sort of correctly.  But nevertheless, it includes two significant errors.  These errors will be corrected in the next two pages of the tutorial.

Return to Jerry's Home Page

This page last edited on 22 Mar 2016.