We are going to write a program that starts multiple threads with exactly the same code. Although they are programmed to execute exactly the same code, our example setup function will only be called once:
- First, we need to include all the necessary headers:
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
using namespace std;
- We are going to use std::call_once later. In order to use it, we need an instance of once_flag somewhere. It is needed for the synchronization of all threads that use call_once on a specific function:
once_flag callflag;
- The function which must be only executed once is the following one. It just prints a single exclamation mark:
static void once_print()
{
cout << '!';
}
- All threads will execute the print function. The first thing we do is calling the function once_print through the function std::call_once. call_once needs the variable callflag we defined before. It will use it to orchestrate the threads:
static void print(size_t x)
{
std::call_once(callflag, once_print);
cout << x;
}
- Ok, let's now start 10 threads which all use the print function:
int main()
{
vector<thread> v;
for (size_t i {0}; i < 10; ++i) {
v.emplace_back(print, i);
}
for (auto &t : v) { t.join(); }
cout << 'n';
}
- Compiling and running yields the following output. First, we see the exclamation mark from the once_print function. Then we see all thread IDs. call_once did not only make sure that once_print was only called once. Additionally, it synchronized all threads, so that no ID is printed before once_print was executed:
$ ./call_once
!1239406758