c++c++20

std synchronisation constructs - logic behind wait() and try_wait_for()


I want to wait once for results of multiple other threads. A std::latch would be a suitable construct - the waiting one uses wait() the producer count_down(), but I want be able to define a timeout so I need wait_for functionallity. Unfortunately std::latch has no wait_for. Well std::semaphore has, but usually std::semaphore is used in inverse logic. It would fit if I could use a negative initialisation value but even it is a signed type (ptrdiff_t) it's not allowed - precondition: desired >= 0. std::atomic wait() - could solve all sync tasks, but .. no wait_for. Seems I need to build my own latch with std::condition_variable and std::mutex.

But I like to understand why some constructs offer timeout functionality (semaphore, mutex, conditional) and others (latch, barrier, atomic wait) do not - is there a reason or just because?

Edit Seems I'm not the only one who likes to have timed operations on atomics: Timed waiting APIs (try_wait, wait_for, and wait_until) for std::atomic are proposed in P2643, targeting C++26. (stack overflow / C++20: How to wait on an atomic object with timeout?

Interprocess use (shared memory) of atomic-wait would be a real dream ;-)


Solution

  • The reason why std::latch and std::barrier don’t include a wait_for method mostly comes down to their design and purpose. These tools are meant to keep thread synchronization simple. A std::latch is just a one-time checkpoint, and a std::barrier works across multiple phases. Adding timeouts would make them more complicated, which goes against their minimal and straightforward design.

    Unlike things like std::condition_variable or std::semaphore, which rely on certain conditions being met (and might never happen), std::latch and std::barrier are more state-based. They assume that all threads will eventually arrive, so there's less need for timeouts. If you think about it, timeouts are super useful to avoid stuff like deadlocks, but with these constructs, it's kind of assumed you’re already managing the threads properly to avoid that problem.

    If you ever need something like a latch but with a timeout, you can build one yourself using tools like std::mutex and std::condition_variable. For example, you could write a simple TimedLatch class that lets you wait for a set number of threads but also gives up if it takes too long. It’s a bit of extra work, but it gives you that extra flexibility when you need it.