September 28, 2020

Banner C++11 Threading

Do you know how to create a thread in C++11? During this post, we will review together the different manner to use the class thread.

We will concentrate on the first purpose: The thread creation!

The Thread library - Create a thread in C++11.

The thread creation is cooked by the constructor of std::thread. To use this library, you should gather two conditions:

1 - The inclusion of the “thread” header.

C++ - Thread requirement

#include <thread>

2 - "std::thread" uses directly the POSIX thread implementation. Then, you must link "pthread".

Bash - How to build with thread - GCC example

g++ -lpthread myCode.cpp

To create a single thread C++11, the std::thread” object constructor needs two parameters:

  • fn - A callable object. It can be a pointer to a function or class member. The return value of this callable object is ignored.
  • args… (optional) - The list of arguments.

If you remember my post about “invoke and apply in C++17”, the callable object is similar to invoke!
Now, let's review the different manners to use the thread class!

Function without arguments.

In C++11, the creation of a thread is pretty simple. You just need a function that returns "void". Unfortunately, You cannot get the returned value. Let's see this basic example below:

C++ - Thread creation with a function

#include <iostream>
#include <thread>

void function_threaded()
{
    std::cout << "(THREAD) Hey, I am thread!" << std::endl;
}

int main()
{
    std::cout << "(MAIN) Hey, I am main!" << std::endl;
    std::thread thread_object(function_threaded);
    // Join the thread. Then, we will wait for the thread termination
    thread_object.join();
    std::cout << "(MAIN) Thread ended!" << std::endl;
    return 0;
}

Here, the object "std::thread" immediately creates and initializes the thread. Here, the thread calls the function "function_threaded".

Output

(MAIN) Hey, I am main!
(THREAD) Hey, I am thread!
(MAIN) Thread ended!

Function with arguments.

Sometimes, the passage of arguments is necessary.

C++ - Thread creation with a function plus arguments

#include <iostream>
#include <thread>

void function_threaded(int a)
{
    std::cout << "(THREAD) Hey, I am thread!" << std::endl;
    std::cout <<"(THREAD) a = " << a << std::endl;
}

int main()
{
    std::cout << "(MAIN) Hey, I am main!" << std::endl;
    std::thread thread_object(function_threaded, 42);
    // Join the thread. Then, we will wait for the thread termination
    thread_object.join();
    std::cout << "(MAIN) Thread ended!" << std::endl;
    return 0;
}

As you see, the example is pretty similar to an initialization without arguments. Compared to the "pthread" implementation, the usage of std::thread simplifies this kind of scenario!

Output

(MAIN) Hey, I am main!
(THREAD) Hey, I am thread!
(THREAD) a = 42
(MAIN) Thread ended!

Class members.

You can initialize a thread by calling a class member:

C++ - Thread creation with a class member

#include <iostream>
#include <thread>

class rectangle
{
    public:
        rectangle(unsigned int height, unsigned int width)
            : height(height), width(width)
            {};
        virtual ~rectangle() {};
        void print_area();
    private:
        unsigned int height;
        unsigned int width;
};

void rectangle::print_area()
{
    unsigned long area = height * width;
    std::cout << "(THREAD) My area is equal to " << area << std::endl;
}

int main()
{
    std::cout << "(MAIN) Hey, I am main!" << std::endl;
    rectangle golden_rectangle(16, 9);
    std::thread thread_object(&rectangle::print_area, golden_rectangle);
    
    thread_object.join();
    std::cout << "(MAIN) Thread ended!" << std::endl;
    return 0;
}

Here a bit more complex. You should at first define the member called. Then, you pass the class object to use. Here, the rectangle area is calculated in a separate thread.

Output

(MAIN) Hey, I am main!
(THREAD) My area is equal to 144
(MAIN) Thread ended!

Lambda expressions.

The lambda expressions can be used for your initialization.

C++ - Thread creation with a lambda expression

#include <iostream>
#include <thread>

int main()
{
    std::cout << "(MAIN) Hey, I am main!" << std::endl;

    std::thread thread_object([](){
        std::cout << "(THREAD) I am the thread!" << std::endl;
    };

    thread_object.join();
    std::cout << "(MAIN) Thread ended!" << std::endl;

    return 0;
}

Output

(MAIN) Hey, I am main!
(THREAD) I am the thread!
(MAIN) Thread ended!

The Thread library - Synchronization and ID.

The object "std::thread" contains two useful members for debug and synchronization:

"join" - Synchronize your thread termination.

Join is a public member of the Thread class. The goal of "join" is to stop your caller until that the thread contained in the object is terminated. You can see the usage of "join" in all my examples.

Remember, as I explained before in this post, "join" is extremely important to terminate properly your thread!

"get_id" - Get your thread ID.

As join, get_id is a public member of the Thread class. Pretty useful for debug, get_id retrieves the thread number.

C++ - Thread ID

#include <iostream>
#include <thread>

void function_threaded()
{
    int j = 0;

    for (int i = 0; i < 10000000; ++i)
    {
        j = j + i;
    }
    std::cout << "(THREAD) I am a thread with the ID: " << std::this_thread::get_id() << std::endl;

}

int main()
{
    std::cout << "(MAIN) Hey, I am main!" << std::endl;
    std::thread thread_object(function_threaded);
    std::cout << "(MAIN) I created a thread with the ID: " << thread_object.get_id() << std::endl;
    // Join the thread. Then, we will wait for the thread termination
    thread_object.join();
    std::cout << "(MAIN) Thread ended!" << std::endl;
    return 0;
}

In this example, I create a thread with the function "function_threaded". With "thread_object.get_id()", the "thread creator" can retrieve the "Thread ID".
To get the "Thread ID" inside my thread, I can use "std::this_thread::get_id()".

Output

(MAIN) Hey, I am main!
(MAIN) I created a thread with the ID: 139815045957376
(THREAD) I am a thread with the ID: 139815045957376
(MAIN) Thread ended!

Advanced usage - Create multiple workers in an array.

Sometimes, you need to create a cluster of workers (placed in vector, map, or array!). You will see with C++11, the creation of those kinds of arrays are pretty simple and powerful. Let's review together two manners to create those workers:

Workers inside a vector with lambda.

C++ - Multiple thread creation with a vector, lambda used

#include <iostream>
#include <vector>
#include <thread>

void threaded_function(int i)
{
    std::cout << "(THREAD) I am thread number " << i << std::endl;
    int j = 1;
    for (int i = 0; i < 100000; ++i)
    {
        j = i*j;
    }
    std::cout << "(THREAD) thread number " << i << " terminated" << std::endl;
}

int main()
{
    std::cout << "(MAIN) Hey, I am main!" << std::endl;
    std::vector<std::thread> vector_of_threads;

    for (int i = 0; i < 5; ++i) {
        vector_of_threads.push_back(std::thread([i](){
            threaded_function(i);
       }));
    }

    // Wait for all thread termination
    for (auto& x: vector_of_threads)
    {
        x.join();
    }

    std::cout << "(MAIN) Exiting" << std::endl;

    return 0;
}

It is a simple extension of my example with lambda expressions and argument usage! I created 5 workers with a different identifier for each one.
Then, the "std::thread" object is directly pushed in my vector. Thanks to this vector, I can "join" those workers.

Output

(MAIN) Hey, I am main!
(THREAD) I am thread number 0
(THREAD) I am thread number 1
(THREAD) I am thread number 2
(THREAD) I am thread number 3
(THREAD) thread number 0 terminated
(THREAD) I am thread number 4
(THREAD) thread number 1 terminated
(THREAD) thread number 2 terminated
(THREAD) thread number 3 terminated
(THREAD) thread number 4 terminated
(MAIN) Exiting

Workers inside a vector without lambda.

Of course, you can also create multiple threads without lambda.
Here, a similar example based the method "emplace_back" from "std::vector" to create your cluster.

C++ - Multiple thread creation with a vector

#include <iostream>
#include <vector>
#include <thread>

void multiplication_threaded(int a, int b)
{
    long multiplication_result = a * b;
    std::cout << "(THREAD) Hey, I am thread! My Result is = " << multiplication_result << std::endl;
}

int main()
{
    std::cout << "(MAIN) Hey, I am main!" << std::endl;
    std::vector<std::thread> thread_list;

    for (int i = 0; i < 5; ++i)
    {
        thread_list.emplace_back(multiplication_threaded, i, 2);
    }

    // Wait for all thread termination
    for (auto& x: thread_list)
    {
        x.join();
    }

    return 0;
}

Output

(MAIN) Hey, I am main!
(THREAD) Hey, I am thread! My Result is = 0
(THREAD) Hey, I am thread! My Result is = 2
(THREAD) Hey, I am thread! My Result is = 4
(THREAD) Hey, I am thread! My Result is = 6
(THREAD) Hey, I am thread! My Result is = 8

About the author 

Axel Fortun

​Developer specialized in Linux environment and embedded systems.
​Knowledge in multiple languages as C/C++, Java, Python​ and AngularJs.
​Working as Software developer since 2014 with a beginning in the car industry​ and then in ​medical systems.