Точный сон с отменой - PullRequest
1 голос
/ 18 мая 2019

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

Вот мой код:

bool cancel_flag(false);

void My_Sleep(unsigned int duration)
{
  static const size_t SLEEP_INTERVAL = 10U; // 10 milliseconds
  while ((!cancel_flag) && (duration > SLEEP_INTERVAL))
  {
    Sleep(duration);
    duration -= SLEEP_INTERVAL;
  }
  if ((!cancel_flag) && (duration > 0U))
  {
    Sleep(duration);
  }
}

Вышеуказанная функция запускается в рабочем потоке. Основной поток может изменить значение «cancel_flag», чтобы прервать (отменить) спящий режим.

В моем магазине у нас разные результаты, когда продолжительность составляет 10 секунд (10000 мс). Некоторые компьютеры показывают продолжительность сна 10 секунд, другие компьютеры показывают 16 секунд.

В статьях о функции Sleep () говорится, что она привязана к прерыванию окон, и по истечении этого срока поток переносится (может быть запущен не сразу). Приведенная выше функция может столкнуться с распространением временной ошибки из-за перепланирования и задержки прерывания.

Проект отметки времени Windows описывает другой метод ожидания объекта таймера. Насколько я понимаю, этот метод не предоставляет средства отмены (другим, основным, потоком).

Вопрос:
1. Как я могу улучшить свою реализацию для задержки потока или сна, которая может быть отменена другой задачей, и является более согласованным ?

  1. Можно ли прекратить спящий поток AFX?
    (Что происходит, когда основной поток завершает спящий поток AFX?)

  2. Что происходит, когда основной поток завершает поток, вызвавший WaitForSingleObject?

Точность должна составлять около 10 мс, например, 10 секунд + 10 мс.
Результаты должны быть одинаковыми на разных ПК (все под управлением Windows 7 или 10).

Фон
ПК с правильной синхронизацией работают под управлением Windows 7 с частотой 2,9 ГГц.
ПК с неправильной синхронизацией работают под управлением Windows 7 с тактовой частотой 3,1 ГГц и имеют меньше одновременных задач и приложений.
Приложение разработано с использованием Visual Studio 2017 и платформы MFC (с использованием AFX для создания потоков).

Ответы [ 2 ]

0 голосов
/ 18 мая 2019
  • Как я могу улучшить мою реализацию для задержки потока или сна, чтобы может быть отменено другой задачей, и является более последовательным?

    • Высокоточный сон обсуждался здесь ранее. Я использовал подход таймера ожидания, похожий на описанный здесь .
  • Можно ли прекратить спящий поток AFX? (Что происходит, когда основной поток прерывает спящий поток AFX?)

    • Я полагаю, вы имеете в виду завершить с TerminateThread? Потоки AFX - это просто обертки вокруг стандартных потоков Windows. В них нет ничего особенного или волшебного, что могло бы дифференцировать их поведение. Итак, что случилось бы, это куча плохих вещей :
      • Если целевой поток владеет критической секцией, критическая секция не будет освобождена.
      • Если целевой поток выделяет память из кучи, блокировка кучи не снимается.
      • Если целевой поток выполняет определенные вызовы kernel32, когда он завершается, состояние kernel32 для процесса потока может быть несовместимым.
      • Если целевой поток манипулирует глобальным состоянием общей библиотеки DLL, состояние библиотеки DLL может быть уничтожено, что повлияет на других пользователей библиотеки DLL.
    • Вам никогда не придется делать это, если у вас есть доступ ко всему исходному коду приложения.
  • Что происходит, когда основной поток завершает поток, вызвавший WaitForSingleObject

0 голосов
/ 18 мая 2019

Вы не должны реализовывать это вообще.

В C ++ 11 все основные необходимые утилиты для многопоточности реализованы в стандарте.Если вы не используете C ++ 11 - затем переключитесь на C ++ 11 или выше - в неудачном случае, что вы не можете, тогда используйте Boost , который имеет те же функции.

В основномто, что вы хотите сделать с этой функциональностью, покрыто std::condition_variable.Вы можете перевести поток в режим ожидания, используя функцию wait (она принимает условную функцию, необходимую для выхода из режима ожидания), wait_for и wait_until (аналогично wait, но с общим временем ожидания), а такжеnotify_one и notify_all методы, которые пробуждают спящие потоки (один или все) и заставляют их проверять состояние пробуждения и выполнять свои задачи.

Проверьте std::conditional_variable в справочнике.Просто Google, и вы найдете достаточно информации об этом с примерами.

Если по какой-то причине вы не доверяете реализации std::conditional_variable, вы все равно можете использовать ее для мини-ожидания и пробуждения.

...