Launching a thread in C/C++
Tags: posix, c, cpp
Published: 2022-09-23 10:47:37

*Note: Since I decided to write a series about multithreading in C/C++, I’m going to rewrite this article.*

## Introduction
Talking about multithreading in C/C++, there are two *standards* that specify the APIs for multithreading:
- [POSIX Threads](https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/): commonly known as Pthreads, is a part of the POSIX Standard.
- ISO C++ (since [C++11](https://www.iso.org/standard/50372.html)): yes, C++ now has *built-in* support for multithreading, I'm going to call it *C++ Thread* for short.

In C, you can use Pthreads. In C++, you have a choice between Pthreads and C++ Thread. The *implementations* for the two standards can be found on most major systems, from PC (macOS, FreeBSD, Linux, ...) to automotive (AutoSAR Adaptive Platform, ...). If you're an Android platform developer and working on AOSP, you might have been working with them already. If your system doesn't support Pthreads, you have an option to use platform-specific thread APIs in C, or you can write in C++ and do multithreading using C++ Thread.

In this post, I'm going to show you some basic examples of both standards to create and launch a new thread. I also remind you to handle the error which might happen. I assumed that you already know how to compile these examples. If you don't, leave a comment.

## Launching a thread using Pthreads
We call the function `pthread_create` to create a new POSIX thread and launch it. The declaration of the function is:

```c
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
```

By presenting it this way, I mean that `pthread_create` is declared in the header file `pthread.h` and it needs 4 parameters to create a new thread:
- `pthread_t *thread` is the pointer to the thread identifier which we are about to receive, so it cannot be `NULL`.
- `const pthread_attr_t *attr` is the attribute object. If it's `NULL`, the default attributes are used. The newly created thread will have these attributes set by `pthread_create`.
- `void *(*start_routine)(void *)` is the function to be executed in the new thread, so it cannot be `NULL`.
- `void *arg` allows us to pass an argument to the `start_routine` function. Because its type is declared as `void *`, you can pass any value which has the same size as `size_t`, or a pointer to any type of object. If `arg` is a pointer, you must make sure the data that `arg` points to remains valid during the execution of the `start_routine` function.

`pthread_create` returns `0` if it successfully created a new thread. Otherwise, an error number will be returned to indicate the error. These numbers are defined in `errno.h`. The error numbers that `pthread_create` can return are:
- `EAGAIN`: The system lacked the necessary resources to create a new thread, or the process reaches its quota (`PTHREAD_THREADS_MAX`).
- `EPERM`: The caller does not have permission to set the required scheduling parameters or scheduling policy.
- `EINVAL`: Invalid attribute(s).

It's bad practice if you don't check and handle the error number that `pthread_create` returns. But for the sake of complexity, in the following example, I'd leave the error handling for the caller of the `launchMyThread()` function:

```c
#include <pthread.h>
#include <stdio.h>

pthread_t myThread;
/**
 * `myThread`'s routine
 */
void *doSomething(void *arg) {
  (void)(arg); /* To avoid a compiler warning that said argument `arg` is unused */
  printf("[%s:%d %s]\n", __FILE__, __LINE__, __FUNCTION__);
  /* In this example, `doSomething` just returns `0` to indicate a successful execution */
  return (void *)0;
}

/**
 * Launch myThread
 * @return 0        : success
 *         non-zero : failure, see errno.h
 */
int launchMyThread() {
  /* `myThread`'s initial attributes */
  pthread_attr_t attr;
  int exitCode = 0;

  pthread_attr_init(&attr);
  /* one of `myThread`'s attributes will be joinable, meaning the calling thread must wait for it to return */
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  exitCode = pthread_create(&myThread, &attr, &doSomething, NULL);
  /* the caller must handle the error */
  return exitCode;
}
```

There are two Pthreads functions that I have yet to mention: `pthread_attr_init()`, `pthread_attr_setdetachstate`. They will be covered in an upcoming post.
Now, move on to the next section to see how to achieve the same using C++ Thread.

## Launching a thread using C++ Thread
C++ provides the `std::thread` class (defined in `<thread>`) to manage the thread of execution. To create a thread, we construct an object of the `std::thread` class. The constructors look like this:
```c++
thread() noexcept; // Default constructor
template<typename Callable,typename Args...>
explicit thread(Callable&& func, Args&&... args); // Second constructor
thread(thread const& other) = delete; // No copy constructor
thread(thread&& other) noexcept; // Move constructor
```
The first constructor constructs an object, but it's not associated with any thread of execution. It is there for constructing an object without anything to execute.
The second one constructs an object that's associated with a thread of execution because it has enough information to do so:
- `Callable&& func`: an [callable object](https://learn.microsoft.com/en-us/cpp/standard-library/is-invocable-classes).
- `Args&&... args`: some arguments. They're optional. You may pass no argument.
`func` and each element of `args` must be [`MoveConstructible`](https://learn.microsoft.com/en-us/cpp/standard-library/is-move-constructible-class).

> **Note**  
> A `MoveConstructible` (since C++11) object is a object that can be constructed from a [rvalue](https://learn.microsoft.com/en-us/cpp/cpp/lvalues-and-rvalues-visual-cpp) argument.  
> The `&&` operator, in this case, is the [*rvalue reference declarator*](https://learn.microsoft.com/en-us/cpp/cpp/rvalue-reference-declarator-amp-amp).  
> But what exactly are they? What do they do here? Well, I will cover this in another post called **Move Semantics in C++**.  

Let's take a look at the following example:

```c++
#include <iostream>
#include <system_error>
#include <thread>

class BackgroundTask {
public:
  void doSomething();
  void doAnotherThing();
  void operator()() const {
    doSomething();
    doAnotherThing();
  }
};

int launchMyThread() {
  try {
    BackgroundTask task;
    // `task` is copied into `myThread`'s storage, so make sure the copy behaves
    // equivalently to the original
    std::thread myThread(task);
  } catch (std::system_error error) {
    std::cout << error.what() << std::endl;
    return -1;
  }

  return 0;
}
```

This is not the simplest example of launching a thread using C++ Thread. But it sure shows some differences between C-style code and C++ style. First, it constructs a `BackgroundTask` object, which is callable because the class overrides the function call operator `()`. Of course, you can also pass a function, or a lambda expression, anything that is callable. The callable object is copied into the storage belonging to the newly created thread of execution and invoked from there. Therefore, you need to ensure that the copy behaves equivalently to the original, or the result may not be what you expect.

The example also shows that is optional to pass arguments. But if you need to, you can pass more than one argument, unlike `pthread_create`, which only allows you to pass only one argument. To receive arguments, the class `BackgroundTask` needs to override the function call operator with parameter(s):

```c++
#include <iostream>
#include <string>
#include <system_error>
#include <thread>

class BackgroundTask {
public:
  void operator()(std::string_view name) const {
    std::cout << "Hello " << name << std::endl;
  }
};

int launchMyThread() {
  try {
    BackgroundTask task;
    std::thread myThread(task, "Multithreading World");
  } catch (std::system_error error) {
    std::cout << error.what() << std::endl;
    return -1;
  }

  return 0;
}
```

It's also bad practice if you don't do the error handling, in this case, exception handling. The second constructor throws a `std::system_error` exception if it's unable to start the new thread, or if there's an exception while copying `func` or `args` into local storage.

> 📝 Never forget to handle errors or exceptions. Spend more time writing error/exception handling and you will spend less time investigating bugs.  

So that's how you create and launch a new thread of execution, using Pthreads/C++ Thread. There's more about multithreading in C/C++. Stay tuned for updates!