Since std::chrono::sleep_for
accepts microseconds, I expected it to be able to sleep for microseconds with some reasonable bias (sleep a little longer, definitely not shorter).
However, it turned out that I was wrong and it seems to be not possible with STL. MSVC implementation of sleep_for
makes the thread to sleep for a few milliseconds (!!!). MinGW implementation bluntly ignores sleep_for
command for microseconds, 1 millisecond, and have been noticed several times to wake up spuriously (though such behavior is not specified by the standard).
When MinGW is told to sleep for 1 millisecond, it sleeps unreasonably longer than 1 millisecond or MSVC.
Here is a code snippet that I use for testing
#include <thread>
#include <condition_variable>
#include <chrono>
#include <iostream>
#include <locale>
struct separate_thousands : std::numpunct<char>
{
char_type do_thousands_sep() const override { return ','; } // separate with commas
string_type do_grouping() const override { return "\3"; } // groups of 3 digit
};
class StopWatch
{
std::chrono::steady_clock::time_point start_;
public:
StopWatch()
: start_(std::chrono::steady_clock::now())
{}
void Reset()
{
start_ = std::chrono::steady_clock::now();
}
std::chrono::nanoseconds Result() const
{
return std::chrono::steady_clock::now() - start_;
}
template <typename MetricPrefix>
std::chrono::duration<long long, MetricPrefix> Result(MetricPrefix) const
{
return std::chrono::duration_cast<
std::chrono::duration<long long, MetricPrefix>
>(Result());
}
template <typename MetricPrefix>
operator std::chrono::duration<long long, MetricPrefix>() const
{
return Result(MetricPrefix());
}
};
template <typename DurationType>
std::chrono::nanoseconds SleepFor(DurationType duration)
{
StopWatch sw{};
std::this_thread::sleep_for(duration);
return sw;
}
template <typename DurationType>
std::chrono::nanoseconds WaitFor(DurationType duration)
{
std::mutex cvMutex{};
std::condition_variable cv{};
StopWatch sw{};
std::unique_lock<std::mutex> ul{cvMutex};
cv.wait_for(ul, std::chrono::microseconds(1));
return sw;
}
int main()
{
std::cout.imbue(std::locale(std::cin.getloc(), new separate_thousands()));
StopWatch sw{};
std::chrono::nanoseconds durationNanosec = sw;
std::cout << "Duration between 2 \"std::chrono::steady_clock::now()\" calls: " <<
durationNanosec.count() << " nanoseconds" << std::endl;
std::cout << "Duration of sleep_for 1 microsecond "
<< SleepFor(std::chrono::microseconds(1)).count()
<< " nanoseconds" << std::endl;
std::cout << "Duration of sleep_for 5 microseconds "
<< SleepFor(std::chrono::microseconds(5)).count()
<< " nanoseconds" << std::endl;
std::cout << "Duration of sleep_for 100 microseconds "
<< SleepFor(std::chrono::microseconds(100)).count()
<< " nanoseconds" << std::endl;
std::cout << "Duration of sleep_for 500 microseconds "
<< SleepFor(std::chrono::microseconds(500)).count()
<< " nanoseconds" << std::endl;
std::cout << "Duration of sleep_for 1 milliseconds "
<< SleepFor(std::chrono::milliseconds(1)).count()
<< " nanoseconds" << std::endl;
// this executes far longer than 1 second on MinGW!
for (size_t i = 0; i != 1000; ++i)
{
std::chrono::nanoseconds duration = SleepFor(std::chrono::milliseconds(1));
if (duration < std::chrono::milliseconds(1))
{
std::cout << "Slept less than 1ms : " << duration.count() << " nanoseconds" << std::endl;
break;
}
}
// this executes far longer than 2 seconds on MinGW!
for (size_t i = 0; i != 1000; ++i)
{
std::chrono::nanoseconds duration = SleepFor(std::chrono::milliseconds(2));
if (duration < std::chrono::milliseconds(2))
{
std::cout << "Slept less than 2ms : " << duration.count() << " nanoseconds" << std::endl;
break;
}
}
std::cout << "Duration of sleep_for 10 milliseconds "
<< SleepFor(std::chrono::milliseconds(10)).count()
<< " nanoseconds" << std::endl;
std::cout << "Duration of condition_variable::wait_for 1 microsecond "
<< WaitFor(std::chrono::microseconds(1)).count()
<< " nanoseconds" << std::endl;
std::cout << "Duration of condition_variable::wait_for 5 microseconds "
<< WaitFor(std::chrono::microseconds(5)).count()
<< " nanoseconds" << std::endl;
std::cout << "Duration of condition_variable::wait_for 1 millisecond "
<< WaitFor(std::chrono::milliseconds(1)).count()
<< " nanoseconds" << std::endl;
std::cout << "Duration of condition_variable::wait_for 10 milliseconds "
<< WaitFor(std::chrono::milliseconds(10)).count()
<< " nanoseconds" << std::endl;
return 0;
}
With MinGW the output may be something like this:
Duration between 2 "std::chrono::steady_clock::now()" calls: 100 nanoseconds
Duration of sleep_for 1 microsecond 700 nanoseconds
Duration of sleep_for 5 microseconds 300 nanoseconds
Duration of sleep_for 100 microseconds 400 nanoseconds
Duration of sleep_for 500 microseconds 200 nanoseconds
Duration of sleep_for 1 milliseconds 7,956,100 nanoseconds
Slept less than 2ms : 1,839,900 nanoseconds
Duration of sleep_for 10 milliseconds 20,629,600 nanoseconds
Duration of condition_variable::wait_for 1 microsecond 6,402,400 nanoseconds
Duration of condition_variable::wait_for 5 microseconds 14,985,800 nanoseconds
Duration of condition_variable::wait_for 1 millisecond 13,803,400 nanoseconds
Duration of condition_variable::wait_for 10 milliseconds 14,900,900 nanoseconds
With MSVC:
Duration between 2 "std::chrono::steady_clock::now()" calls: 300 nanoseconds
Duration of sleep_for 1 microsecond 13,200 nanoseconds
Duration of sleep_for 5 microseconds 1,694,100 nanoseconds
Duration of sleep_for 100 microseconds 1,572,900 nanoseconds
Duration of sleep_for 500 microseconds 1,694,300 nanoseconds
Duration of sleep_for 1 milliseconds 1,645,000 nanoseconds
Duration of sleep_for 10 milliseconds 10,976,100 nanoseconds
Duration of condition_variable::wait_for 1 microsecond 46,100 nanoseconds
Duration of condition_variable::wait_for 5 microseconds 21,300 nanoseconds
Duration of condition_variable::wait_for 1 millisecond 28,700 nanoseconds
Duration of condition_variable::wait_for 10 milliseconds 22,500 nanoseconds
I am aware that I can use busy waiting to wait for nanoseconds, but this is a no go, since I do not want to waste CPU resources. Moreover, MinGW implementation seems to provide unpredictable results.
- Is there a way to sleep for microseconds?
- Is there a good crossplatform alternative for STL threads that implements sleeping for microseconds?
Aucun commentaire:
Enregistrer un commentaire