Подтвердить что ты не робот

Когда целесообразно использовать функцию тайм-аута С++ 11 * _until вместо соответствующей функции * _for?

В С++ 11 функции тайм-аута *_until ведут себя "как ожидалось", только если используются устойчивые часы (т.е. тот, который перемещается только вперед с неизменной скоростью). Поскольку system_clock не является постоянным, это означает, что такой код может вести себя довольно удивительно:

using namespace std::chrono;
std::this_thread::sleep_until(system_clock::now() + seconds(10));

Это заставит текущий поток спать в течение 10 секунд, если системные часы не будут отрегулированы во время периода ожидания, например, для летнего времени. Если часы установлены в течение часа во время сна, текущая нить будет спать в течение часа и 10 секунд.

Из того, что я могу сказать, каждая функция тайм-аута *_until в С++ 11 имеет соответствующую функцию *_for, которая занимает длительность вместо временной точки. Например, приведенный выше код можно переписать следующим образом:

using namespace std::chrono;
std::this_thread::sleep_for(seconds(10));

Функции *_for не должны беспокоиться о часах, которые настраиваются во время выполнения функции, потому что они просто говорят, как долго ждать, а не время, которое должно было быть, когда ожидание закончилось.

Эта проблема затрагивает больше, чем функции сна, поскольку то же самое верно для ожидающих ожидания на функциях фьючерсов и try_lock.

Единственная ситуация, в которой я могу представить себе смысл использовать функцию *_until с нестационарными часами, - это когда вы хотите принять во внимание синхронизацию часов, например, вы хотите спать до следующей среды в 3:30 утра, даже если время от времени происходит переход на летнее время или с летнего времени. Существуют ли другие ситуации, когда функции *_until имеют больше смысла, чем функции *_for? Если нет, можно ли с уверенностью сказать, что в функции *_until должны быть предпочтительнее функции тайм-аута *_for?

4b9b3361

Ответ 1

Звонки xxx _until предназначены для тех случаев, когда у вас установлен крайний срок. Типичный пример использования - это то, где у вас есть жесткий временной интервал для раздела кода, который либо содержит несколько ожиданий, либо время, затрачиваемое каждым шагом до ожидания, непредсказуемо.

например.

void foo() {
  std::chrono::steady_clock::time_point const timeout=
    std::chrono::steady_clock::now()+std::chrono::milliseconds(30);

  do_something_which_takes_some_time();

  if(some_future.wait_until(timeout)==std::future_status::ready)
    do_something_with(some_future.get());
}

Это будет обрабатывать только значение из some_future, если оно готово в течение 30 мс с самого начала, включая время, затраченное на do_something_which_takes_some_time().

Как и в этом примере, большинство случаев использования функций xxx _until будут использовать устойчивые часы, чтобы иметь предсказуемый таймаут.

Единственный случай, когда я могу представить, используя функции xxx _until с нестационарными часами (например, std::chrono::system_clock), - это время, когда тайм-аут является видимым пользователем и зависит от значения выбранных часов. Одним из примеров является программа будильника или напоминания, другая программа резервного копирования, которая запускается "в полночь".

Ответ 2

Один прецедент для функции sleep_until - это если вы хотите спать до определенного времени, а не определенной продолжительности.

Например, если у вас есть поток, который должен активироваться только в 3 часа дня каждый день, вам нужно либо рассчитать продолжительность (включая обработку летнего и летнего времени) для использования с sleep_for, либо вы можете использовать sleep_until.

Ответ 3

Одно хорошее применение для sleep_until - в циклах с постоянным временем (например, в игровых циклах). Если вы не уверены, сколько времени займет цикл для обработки, но он, как правило, должен иметь определенную минимальную длину, вы можете увеличить значение time_point, которое должно спать, до цикла. Например:

// requires C++14
#include <iostream>
#include <thread>
#include <chrono>

using namespace std;
using namespace std::chrono;
using namespace std::literals;

int main()
{
  auto start_time = steady_clock::now();

  for (auto i = start_time; i <= start_time + 1s; i += 50ms) {
    this_thread::sleep_until(i);
    cout << "processing cycle..." << endl;
  }

  return 0;
}

Но тогда вам, вероятно, придется следить за задержкой, когда цикл занимает больше времени, чем приращение.

Идея состоит в том, что если вы наивно sleep_for, вы будете спать с периодом цикла плюс время, затрачиваемое на выполнение кода внутри цикла.