mardi 30 mai 2023

Unexpected behavior with `std::chrono::system_clock` and `std::chrono::steady_clock` in `std::condition_variable::wait_until`

I'm working with std::condition_variable::wait_until in C++ and I'm using std::chrono::system_clock and std::chrono::steady_clock to manage the waiting time. After reading the documentation, I understand that the sleeping time should not be affected by changes in the system time when using std::chrono::steady_clock, while it may change when using std::chrono::system_clock.

However, my code is behaving differently: for both clock types, the waiting time is affected by the system time. Here's a minimal reproducible example:

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <ctime>
#include <sys/time.h>
#include <condition_variable>
#include <atomic>

std::atomic<bool> flag = false;
std::condition_variable cv;


void wait_using_system_clock()
{
    std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
    std::mutex mtx;
    std::unique_lock lock(mtx);
    cv.wait_until(lock, std::chrono::system_clock::now() + std::chrono::seconds(20), [](){return flag.load();});

    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
    std::cout << "Time difference [using system clock] = " << std::chrono::duration_cast<std::chrono::seconds>(end - begin).count() << "s" << std::endl;
}

void wait_using_steady_clock()
{
    std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
    std::mutex mtx;
    std::unique_lock lock(mtx);
    cv.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::seconds(20), [](){return flag.load();});

    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
    std::cout << "Time difference [using steady clock] = " << std::chrono::duration_cast<std::chrono::seconds>(end - begin).count() << "s" << std::endl;
}

void set_system_time_forward()
{
    std::this_thread::sleep_for(std::chrono::seconds(2)); // Ensure other threads has executed cv.wait_until
    struct timeval tv;
    gettimeofday(&tv, NULL);
    tv.tv_sec += 15;
    settimeofday(&tv, NULL);
}

int main()
{
    std::thread t1(wait_using_system_clock);
    std::thread t2(wait_using_steady_clock);

    std::thread t3(set_system_time_forward);
    t1.join();
    t2.join();
    t3.join();

    return 0;
}

I execute the wait_using_system_clock and wait_using_steady_clock functions on different threads. Another thread is used to change the system time after 2 seconds. I expect that the function wait_using_steady_clock should not be affected by this change and should wait for 20 seconds, but instead, both functions finish their execution in approximately 5 seconds, printing:

Time difference [using system clock] = 5s
Time difference [using steady clock] = 5s

Can anyone help me understand why this discrepancy exists between the expected and actual behavior? Is there something I'm missing in the documentation or misunderstanding about these classes?

Aucun commentaire:

Enregistrer un commentaire