Выполнение функции в нескольких временных метках

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

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

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

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

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

1

Решение

То, что вы хотите сделать, это реализовать простой планировщик задач.

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

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

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

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

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

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

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

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

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]