Convert between c++11 clocks

前端 未结 2 1773
小鲜肉
小鲜肉 2020-12-14 08:14

If I have a time_point for an arbitrary clock (say high_resolution_clock::time_point), is there a way to convert it to a time_point fo

2条回答
  •  被撕碎了的回忆
    2020-12-14 09:02

    There's no way to do this precisely unless you know the precise duration difference between the two clock's epochs. And you don't know this for high_resolution_clock and system_clock unless is_same{} is true.

    That being said, you can program up an approximately correct translation and it goes much like T.C. says in his comment. Indeed, libc++ plays this trick in its implementation of condition_variable::wait_for:

    https://github.com/llvm-mirror/libcxx/blob/78d6a7767ed57b50122a161b91f59f19c9bd0d19/include/__mutex_base#L455

    The calls to now of the different clocks are made as close together as possible, and one hopes that the thread isn't pre-empted between these two calls for too long. It's the best I know how to do, and the spec has wiggle room in it to allow for these types of shenanigans. E.g. something is allowed to wake up a little late, but not a little early.

    In the case of libc++, the underlying OS only knows how to wait on system_clock::time_point, but the spec says you must wait on steady_clock (for good reasons). So you do what you can.

    Here is a HelloWorld sketch of the idea:

    #include 
    #include 
    
    std::chrono::system_clock::time_point
    to_system(std::chrono::steady_clock::time_point tp)
    {
        using namespace std::chrono;
        auto sys_now = system_clock::now();
        auto sdy_now = steady_clock::now();
        return time_point_cast(tp - sdy_now + sys_now);
    }
    
    std::chrono::steady_clock::time_point
    to_steady(std::chrono::system_clock::time_point tp)
    {
        using namespace std::chrono;
        auto sdy_now = steady_clock::now();
        auto sys_now = system_clock::now();
        return tp - sys_now + sdy_now;
    }
    
    int
    main()
    {
        using namespace std::chrono;
        auto now = system_clock::now();
        std::cout << now.time_since_epoch().count() << '\n';
        auto converted_now = to_system(to_steady(now));
        std::cout << converted_now.time_since_epoch().count() << '\n';
    }
    

    For me, using Apple clang/libc++ at -O3 this output:

    1454985476610067
    1454985476610073
    

    indicating the combined conversion had an error of 6 microseconds.

    Update

    I have arbitrarily reversed the order of the calls to now() in one of the conversions above such that one conversion calls them in one order, and the other calls them in the reverse order. This should have no impact on the accuracy of any one conversion. However when converting both ways as I do in this HelloWorld, there should be a statistical cancellation which helps to reduce the round-trip conversion error.

提交回复
热议问题