Выполнение функции в нескольких временных метках - PullRequest
0 голосов
/ 23 октября 2018

Я пытаюсь реализовать (в C ++ 11/14) способ выполнения функции в нескольких временных метках.Сценарий выглядит следующим образом:

Существует один основной поток, который может получать запросы в любое время.Запросы могут быть в одном из форматов: remove object X at time Y или insert object X at time Y, где X - это идентификатор, который я использовал для идентификации объекта в нашем хранилище, а Y - метка времени Unix.Разрешение по времени будет вторым.

Интуитивно понятным способом было бы создание нового потока всякий раз, когда приходит новый запрос.Затем этот новый поток спит в течение некоторого времени, указанного в запросе, и удаляет / добавляет объект, когда он просыпается.

Другим способом будет опрос.Основной поток может хранить полученные запросы.Затем отдельный поток может проверять все полученные запросы каждую секунду и видеть, нужно ли выполнять какое-либо удаление / вставку.

Кажется, что оба упомянутых мною подхода могут повлечь за собой огромные накладные расходы, поэтому я ищу альтернативный способ.

1 Ответ

0 голосов
/ 23 октября 2018

Что вам нужно сделать, так это реализовать простой планировщик задач.

Самый простой и эффективный способ сделать это - это всего лишь один поток, вызов по принципу «что происходит в текущий момент времени»(например, std :: chrono :: system_clock :: now () ), и математика для добавления и вычитания временных меток:

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

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

  3. Найдите наименьшую временную метку в вашем расписании и вычтите из нее текущее системное время.Если в расписании нет событий вообще, выберите произвольное, но очень продолжительное время, например, 1 час или 1 неделя или т. Д .;или если ваше расчетное значение отрицательное, вместо этого используйте 0.

  4. Сон в течение времени, которое вы рассчитали на шаге 3.

  5. Один развы проснулись ото сна, проверьте отметку времени самого раннего события в вашем расписании.Если оно меньше или равно текущему времени системы, выполните это событие, удалите событие из расписания и перейдите к (5).В противном случае перейдите к (2).

Это должно дать вам необходимое поведение с хорошей точностью и минимальными издержками.Единственная проблема заключается в том, что если другой поток хочет запланировать другую задачу во время работы вашего потока планировщика, ему нужно вывести ваш поток планировщика из спящего режима, чтобы поток планировщика мог сразу же выполнить цикл снова через шаги 2-5 (простоесли вновь вставленное событие должно произойти за до события, которое оно планировало выполнить ранее).Это может быть реализовано, например, с помощью std :: condition_variable и wait_for () или wait_until () в качестве механизма ожидания, а другой поток сигнализируетпеременная условия, если вам нужно, чтобы вы проснулись рано.(Также применяются стандартные предостережения о многопоточности, поэтому обязательно сериализуйте доступ к структуре данных вашего расписания с мьютексом или критическим разделом)

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

...