Tolerable delay in interruptible_wait on Win32 is too long

Open
#348 13 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
38/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Stale
Tech stack
cpp

Research direction

Start with src/win32/thread.cpp around lines 644-652 and trace how interruptible_wait calculates and passes the tolerable value to the Windows wait. Reproduce the reported 20-minute wait on Windows with the supplied example, then verify that the wait no longer adds a systematic delay while preserving interruptible condition-variable behavior.

Written by the indexing model from the issue text.

Description

  • Boost 1.74
  • MSVC 2019
  • Windows 10

We have a thread that shall perform small actions in various time intervals. We implemented it with a condition_variable::wait_for(interval):

bool terminating = false;
void workerMain() {
    while (true) {
        interval = calculate_time_until_next_action();
        if (condition_variable.wait_for(lock, interval, [&]() { return terminating; })) {
            break;
        }
        do_some_action();
    }
}

We noticed rather big delays when doing this with longer times, like several minutes. A wait for 20mins always takes 21mins. This is my reproducer:

boost::mutex m;
boost::condition_variable cv;
boost::unique_lock lock { m };
const boost::chrono::minutes duration { 20 };
const auto start = std::chrono::steady_clock::now();
cv.wait_for(lock, duration);
const auto stop  = std::chrono::steady_clock::now();
std::cout << "took " << std::chrono::duration_cast<std::chrono::duration<double>>(stop - start).count() << "s";

The output clearly shows our issue: "took 1260.32s".

With some further debugging I found that the interally used function boost::this_thread::interruptible_wait() takes too long, and its implementation makes clear where the origin is:
https://github.com/boostorg/thread/blob/4abafccff4bdeb4b5ac516ff0c2bc7c0dad8bafb/src/win32/thread.cpp#L644-L652

The tolerable is used by Windows to save energy using timer coalescing, and my interpretation is that - as our thread is doing nothing else that would create events - Windows waits the full tolerable time until it fires the timer.

Although there is no guarantee that the timed operations wake the thread up at a specific timepoint, in my opinion it is wrong to produce a systematically too late wake-up. The tolerable should me much smaller (like 100ms max), even if I want to wait for an hour.

Dominant language
C++
Stars
213
Forks
171
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from boostorg/thread

All issues in boostorg/thread

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.