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

C++ JThread and Latches

A latch is a counter that threads count down while other code waits for it to reach zero. A jthread is a thread that joins on its own when its scope ends.

A latch gates three workers

Each thread stores one value in its own slot and then counts the latch down. Main waits on the latch and joins the threads before it prints the sum.

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

void fillAndSignal(std::array<int, 3>* slots, std::latch* done, int index, int value) {
  (*slots)[index] = value;
  done->count_down();
}

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

A jthread joins at the end of its scope

The jthread runs a fixed job inside the inner scope and no join call appears. Main prints the stored result after the scope, when the automatic join has finished.

#include <iostream>
#include <thread>

void computeInto(int* result) {
  *result = 6 * 7;
}

int main() {
  int result = 0;
  {
    std::jthread worker(computeInto, &result);
  }
  std::cout << "Result: " << result << std::endl;
  return 0;
}

A stop request on an idle jthread

The jthread runs an empty job that takes a stop token. Main sends a stop request and prints the answer and the state of the token.

#include <iostream>
#include <thread>

int main() {
  std::jthread worker([](std::stop_token token) {
  });
  bool sent = worker.request_stop();
  std::cout << "Stop sent: " << std::boolalpha << sent << std::endl;
  std::cout << "Stop seen: " << std::boolalpha << worker.get_stop_token().stop_requested() << std::endl;
  return 0;
}

Example

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

void fillAndSignal(std::array<int, 2>* slots, std::latch* done, int index, int value) {
  (*slots)[index] = value;
  done->count_down();
}

int main() {
  std::array<int, 2> slots = {0, 0};
  std::latch done(2);
  std::thread first(fillAndSignal, &slots, &done, 0, 14);
  std::thread second(fillAndSignal, &slots, &done, 1, 28);
  done.wait();
  first.join();
  second.join();
  int combined = slots[0] + slots[1];
  std::cout << "First: " << slots[0] << std::endl;
  std::cout << "Second: " << slots[1] << std::endl;
  std::cout << "Combined: " << combined << std::endl;
  return 0;
}

Key points

  • std::latch starts with a fixed count and each count_down call lowers it by one.
  • wait blocks until the latch count reaches zero.
  • std::jthread joins on its own when it goes out of scope and no join call is written.
  • request_stop records a stop request and returns whether the request was made.
  • A worker can read stop_requested on its stop token to see a request.

In this example, two threads each store one value and count the latch down. Main waits for the latch to reach zero and then joins both threads. The stored values are 14 and 28, and the combined total is 42.

Note

These programs read results only after a wait or a join, so every printed value is settled.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What happens when a std::jthread goes out of scope?