๐ŸŽ“ A1Learner
๐Ÿ”
0 of 28 lessons completed

C++ Threads and Join

A thread is a separate line of work that runs alongside the main program. The main program starts a thread with std::thread and waits for it with join.

One thread stores a value

The compute function adds two numbers and stores the result through a pointer. Main joins the thread and only then prints the stored value.

#include <iostream>
#include <thread>

void compute(int* result) {
  *result = 17 + 25;
}

int main() {
  int result = 0;
  std::thread worker(compute, &result);
  worker.join();
  std::cout << "Result: " << result << std::endl;
  return 0;
}

Three threads fill separate slots

Each thread writes one slot of the array and no slot is shared. Main joins all three threads before it prints the slots and their sum.

#include <array>
#include <iostream>
#include <thread>

void fillSlot(std::array<int, 3>* slots, int index, int value) {
  (*slots)[index] = value;
}

int main() {
  std::array<int, 3> slots = {0, 0, 0};
  std::thread first(fillSlot, &slots, 0, 10);
  std::thread second(fillSlot, &slots, 1, 20);
  std::thread third(fillSlot, &slots, 2, 30);
  first.join();
  second.join();
  third.join();
  int sum = slots[0] + slots[1] + slots[2];
  std::cout << "Slots: " << slots[0] << " " << slots[1] << " " << slots[2] << std::endl;
  std::cout << "Sum: " << sum << std::endl;
  return 0;
}

A thread takes an argument

The thread receives a name as an argument and builds a greeting from it. Main prints the greeting after the join.

#include <iostream>
#include <string>
#include <thread>

void buildGreeting(std::string name, std::string* greeting) {
  *greeting = "Hello, " + name;
}

int main() {
  std::string greeting = "";
  std::thread worker(buildGreeting, std::string("Mina"), &greeting);
  worker.join();
  std::cout << greeting << std::endl;
  return 0;
}

Example

#include <array>
#include <iostream>
#include <thread>

void squareInto(int value, int index, std::array<int, 4>* slots) {
  (*slots)[index] = value * value;
}

int main() {
  std::array<int, 4> slots = {0, 0, 0, 0};
  std::thread first(squareInto, 3, 0, &slots);
  std::thread second(squareInto, 5, 1, &slots);
  std::thread third(squareInto, 7, 2, &slots);
  std::thread fourth(squareInto, 9, 3, &slots);
  first.join();
  second.join();
  third.join();
  fourth.join();
  int total = slots[0] + slots[1] + slots[2] + slots[3];
  std::cout << "Squares: " << slots[0] << " " << slots[1] << " " << slots[2] << " " << slots[3] << std::endl;
  std::cout << "Total: " << total << std::endl;
  return 0;
}

Key points

  • std::thread starts a new line of work when the thread object is made.
  • Use join to wait until a thread has finished its work.
  • A value stored by a thread is safe to read after join returns.
  • Each thread in these programs writes only to its own storage.
  • The main program reads results only after every thread has joined.

In this example, four threads each square one number into a separate slot. Main joins all four threads before reading any slot. The printed squares are 9, 25, 49, and 81, and their total is 164.

Note

A thread that is never joined stops the program when its object is destroyed.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Why does main call join before printing a value a thread stored?