[C++] Multithreading and Concurrency: INTRODUCTION

A simple guide to learn C++ multithreading and concurrency without too many headaches

Valentina
Valentina
Oct 13 · 6 min read

When I started studying C++ multithreading I was feeling confused and lost. The complexity of the program was blooming (yes, like a beautiful flower), the non-deterministic behavior of concurrency was killing me and everything was foggy. So I get you and I got you: here is a simple guide to learn C++ concurrency and multithreading without too many headaches (you can find the roadmap at the end of the article).


Today, let’s quickly refresh some basic concepts and then taste a bit of concurrent code.

1. What is a thread?

Upon creation, each process has a unique thread of execution called main thread. It can ask the Operating System to create other threads, that share the same address space of the parent process (code section, data section, other operating-system resources, such as open files and signals). On the other hand, each thread has its own thread ID, stack, register set and program counter. Basically a thread is a light weight process, switching between threads is faster and IPC is easier.

2. What is concurrency?

The scheduler allocates, over time, the use of available cores between different threads in a non-deterministic way. This is called hardware concurrency: multiple threads running on different cores in parallel, each of them taking care of a specific task of the program.
N.B. The std::thread::hardware_concurrency() function is used to know how many tasks the hardware can truly run concurrently. If the number of threads exceed this limit, we will possibly incur in excessive task switching (switching between tasks many times per second to give an illusion of concurrency).

3. Basic thread operations with std::thread

Here you can find a small code example of almost all the above theory.

4. Why is synchronization needed?

With multiple threads sharing the same address space and resources, a lot of operations become critic: multithreading requires synchronization primitives. This is why.

In order to act safely, a thread should declare what is using and check if the object is in use prior to touch it. Is thread Green watching TV? Well, then no one can touch the TV in any way (if anything, others can sit and watch it too). This can be done with a mutex.


Code example

Let’s see some code, so you can test yourself the non-deterministic behavior of multithreading.

A possible output:

   B0
A0
A1
A2
B1
A3
B2
B3

..

Differently from a single-threaded implementation, each execution produces a different and not predictable output (the only certainty is that A lines are sorted in ascending order, as well as B lines). This can cause problems when instruction ordering is important.

Possible output:

..
[ 12 ] value 0
[ 13 ] value 1
[ 14 ] value 0
[ 15 ] value 0
[ 16 ] value 0
[ 17 ] value 0
[ 18 ] value 1
[ 19 ] value 0
..

What happened here? After thread A evaluates “value” as true, thread B changes it. Now we are inside an if-block, even if the constraint has been violated.

If two threads access the same data, one writing and one reading, there is no guarantee on which operation is executed first.

Accesses must be synchronized.

Conclusions

I know these are a lot of concepts. Keep in mind that you don’t need to understand everything right now, but it’s important to grasp the core ideas.
I suggest you to play with the examples and see how concurrency takes action. Also, try to think about other examples where synchronization is needed and test them out (hint: What about multiple threads popping the front of a queue? Remember you must check if the queue is empty before popping).

ROADMAP

I have structured the series as follows:

(The C ++11 library introduces a standard mechanism for synchronization, independent of the underlying platform, so I will not talk about native Linux and Windows threads. Anyway, the core concepts are very similar.)

I will publish one article per week and keep this roadmap updated.

In the next article we will see the mutex synchronization primitive and how to use it at its best.

If you want me to deepen some topic, let me know (you can find me on instagram too, @ valentina.codes).

The Startup

Medium's largest active publication, followed by +525K people. Follow to join our community.

Valentina

Written by

Valentina

Computer engineering student @Polito and @GrenobleINP. Former Wireless Network research assistant @LIG. Passionate in what I do.

The Startup

Medium's largest active publication, followed by +525K people. Follow to join our community.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade