The examples rely on C++11 functionalities for its threads. If you don't have access to C++11 then POSIX and the Windows API have similar capabilities.

I will also use lambda functions which is another C++11 functionality, purely as they make everything "easier" in the sense of small examples. They are of course not required and regular function pointers can be used instead.

If you want more in-depth explanations use the associated links, as this post is intended to be examples and short explanations.

Lifetime

Always make sure that all threads have finished before the program tries to exit. This can be done by blocking the main-thread until all child threads have finished.

Most OSes does indeed take care of the dirty work of terminating threads and freeing memory, but this is considered really bad practice!

Join

Join blocks the thread that called it, until the thread has finished its execution.

If join() isn't called on a thread and the thread leaves the scope thus deleting the thread. That can cause undefined behavior and will most likely trigger a debugging error (In Visual Studio, R6010 - abort() has been called). This is easily fixed by calling join() on the thread(s).

#include <iostream>
#include <thread>
#include <chrono>

int main(int argc, char *argv[])
{
    std::cout << "Starting first thread...\n";
    std::thread t1([]()
    {
        // Do some work
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
    });

    std::cout << "Starting second thread...\n";
    std::thread t2([]()
    {
        // Do some work
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    });

    std::cout << "Waiting for threads to finish...\n";
    t1.join();
    t2.join();

    std::cout << "Both threads have finished!\n";

    return 0;
}

Output:

Starting first thread...
Starting second thread...
Waiting for threads to finish...
Both threads have finished!

Detach

If it's needed that the thread object can leave the scope, then detaching the thread from the thread object is needed.

#include <iostream>
#include <thread>
#include <chrono>

int main(int argc, char *argv[])
{
    std::cout << "Starting thread...\n";

    {
        std::thread t([]()
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(100));

            std::cout << "Thread done!\n";
        });

        std::cout << "Detaching thread...\n";
        t.detach();
    }

    std::cout << "Sleeping...\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(200));

    std::cout << "Done!\n";

    return 0;
}

Possible Output:

Starting thread...
Detaching thread...
Sleeping...
Thread done!
Done!

Mutex

Mutex or Mutual exclusion is a synchronization mechanism which can be used to limit access to certain variables, objects, resource, etc. There exists various kind of mutexes such as locks and semaphores, etc.

The golden rule is to always use a mutex if multiple concurrent processes, is accessing the same variable(s) at the same time, no matter if it's a hashmap, vector or "just" an integer.

Locks

Locks can do exactly what they sound like, they can be locked and unlocked. Any thread can call lock() and unlock() on a mutex at any time.

The thread that locks a mutex is the only thread that can unlock it again. If another thread tries to lock a mutex which is already locked the thread will be put to sleep. When the mutex is unlocked the thread wakes up again.

In C++ std::mutex is just a lock that does so. Though instead of manually locking and unlocking the mutex, I highly encourage anybody to use std::lock_guard as this automatically unlocks the mutex when it leaves the scope. Further std::lock_guard is exception-safe so if an exception is thrown within the thread which isn't try-catch'ed then std::lock_guard will still unlock the mutex, thus not creating a deadlock. Also be aware that if the same thread tries to lock a mutex more than once, it will create a deadlock on itself.

#include <iostream>
#include <thread>

void say(std::string message)
{
    std::cout << message.c_str() << "\n";
}

int main(int argc, char *argv[])
{
    std::thread t1(say, "Hello World!");
    std::thread t2(say, "Vallentin Source");

    t1.join();
    t2.join();

    return 0;
}

Possible Output:

HelVallentin lo World!
Source

The above example has a high chance of outputting gibberish as the threads are "talking over each other". This is something that can easily be solved by using a lock.

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mutex;

void say(std::string message)
{
    // mutex.lock();
    std::lock_guard<std::mutex> lock(mutex);

    std::cout << message.c_str() << "\n";

    // mutex.unlock();
}

int main(int argc, char *argv[])
{
    std::thread t1(say, "Hello World!");
    std::thread t2(say, "Vallentin Source");

    t1.join();
    t2.join();

    return 0;
}

Output:

Hello World!
Vallentin Source

Recursive Locks

Recursive Locks also called Reentrant Mutex is a mutex which allows the same thread to lock it multiple times, without resulting in a deadlock. This is handy if the mutex is shared/locked by multiple functions which call each other.

The following is probably not something anybody would ever need to do, but it's just an example! If we replace recursive_mutex with mutex we encounter the problem.

std::recursive_mutex mutex;

float min(float a, float b)
{
    std::lock_guard<std::recursive_mutex> lock(mutex);

    return ((a < b) ? a : b);
}

float min(float a, float b, float c)
{
    std::lock_guard<std::recursive_mutex> lock(mutex);

    return min(a, min(b, c));
}

Try Lock

Any C++11 mutex has a bool try_lock() member function. This function tries to lock the mutex and returns true if is was successfully locked, otherwise it returns false. This means that the thread isn't put to sleep if it can't acquire a successful lock.

std::mutex mutex;

void test(void)
{
    if (mutex.try_lock(timeout))
    {
        // lock acquired

        mutex.unlock(); // remember to unlock it again
    }
    else {} // failed
}

Timed Locks

Timed Locks are built upon the try_lock() functionality, expanding it by adding a timeout duration. The difference between try_lock_for() and try_lock() is that try_lock_for() will continue to try and acquire a lock until the specified timeout duration has elapsed.

std::timed_mutex mutex;

void test(void)
{
    std::chrono::microseconds timeout = std::chrono::milliseconds(1000);

    if (mutex.try_lock_for(timeout))
    {
        // lock acquired

        mutex.unlock(); // remember to unlock it again
    }
    else {} // failed
}

Further there's also something called a Recursive Timed Mutex.

Condition Variable

Condition Variable is a list of threads which is waiting until another thread notifies them to continue. Condition Variables kinda works in the opposite sense of mutexes. With mutexes only one of the locked threads continue when the mutex is unlocked. Though with a Condition Variable all threads continue when the Condition Variable get notified (Though you can notify a single thread, instead of them all as well).

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mutex;
std::condition_variable cv;
bool ready = false;

void thread_id(int id)
{
    std::unique_lock<std::mutex> lock(mutex);

    // while (!ready) { cv.wait(lock); }
    // or
    cv.wait(lock, []{ return ready; });

    std::cout << "Thread #" << id << '\n';
}

void start(void)
{
    std::unique_lock<std::mutex> lock(mutex);

    ready = true;
    cv.notify_all();
}

int main(int argc, char *argv[])
{
    const int n = 10;
    std::thread threads[n];

    for (int i = 0; i < n; i++)
    {
        threads[i] = std::thread(thread_id, i);
    }

    std::cout << "All threads are ready...\n";
    start();

    for (std::thread &t : threads)
    {
        t.join();
    }

    std::cout << "Done!\n";

    return 0;
}

Possible Output (The order may vary):

All threads are ready...
Thread #9
Thread #7
Thread #5
Thread #3
Thread #0
Thread #1
Thread #2
Thread #4
Thread #6
Thread #8
Done!

Call Once

Call once insures that a Callable is only called once even when doing multithreading. Also note that if an exception is thrown from the call once function, then it doesn't as being called!

#include <iostream>
#include <thread>
#include <mutex>

std::once_flag flag;

void call_once(void)
{
    std::cout << "Called once!\n";
}

void call_each(void)
{
    std::call_once(flag, call_once);

    std::cout << "Called each time...\n";
}

int main(int argc, char *argv[])
{
    std::thread t1(call_each);
    std::thread t2(call_each);
    std::thread t3(call_each);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}

Output:

Called once!
Called each time...
Called each time...
Called each time...

Sleep

As of C++11 there's also a standard sleep functionality.

#include <thread>
#include <chrono>

void test(void)
{
    // Sleep for 100 milliseconds
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    // Sleep for 2 seconds
    std::this_thread::sleep_for(std::chrono::seconds(2));

    // Sleep for 1 hour
    std::this_thread::sleep_for(std::chrono::hours(1));
}

Number of Concurrent Threads

With C++11 you can easily check how many concurrent threads the system supports, which then can be used to limit the amount of threads for the best performance.

unsigned int n = std::thread::hardware_concurrency();

std::cout << n << " concurrent threads are supported.\n";

Note that hardware_concurrency() returns 0 if it can't detect how many concurrent threads the system supports.