Дросселирование процессора в C++

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

Прямо сейчас я обнаружил самый трудоемкий цикл в потоке (он выполняет только сжатие) и использую GetTickCount() и Sleep() с жестко запрограммированными значениями. Он гарантирует, что цикл продолжается в течение определенного периода, а затем находится в спящем режиме в течение определенного минимального времени. Он более или менее выполняет свою работу, т.е. гарантирует, что поток не будет использовать более 50% ЦП.
Однако поведение зависит от количества ядер процессора (огромный недостаток) и просто некрасиво (меньший недостаток :)).
Любые идеи?

Ответов (5)

Решение

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

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

  1. Вычислите количество процессорного времени, которое ваш поток использовал с момента последнего вызова вашей функции регулирования (я назову это dCPU). Вы можете использовать API GetThreadTimes (), чтобы узнать количество времени, в течение которого ваш поток выполнялся.
  2. Вычислите количество реального времени, прошедшего с момента последнего вызова вашей функции регулирования (я назову это dClock).
  3. dCPU / dClock - это процент использования ЦП (одного ЦП). Если оно выше, чем вы хотите, увеличьте время сна, если оно меньше, уменьшите время сна.
  4. Заставьте ваш поток спать на вычисленное время.

В зависимости от того, как ваш сторожевой таймер вычисляет использование ЦП, вы можете использовать GetProcessAffinityMask (), чтобы узнать, сколько ЦП имеет система. dCPU / (dClock * CPUs) - это процент от общего доступного процессорного времени.

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

Я не могу придумать какой-либо кроссплатформенный способ того, что вы хотите (или любой гарантированный способ полной остановки), но, поскольку вы используете GetTickCount, возможно, вас не интересует кросс-платформа :)

Я бы использовал межпроцессное взаимодействие и установил хорошие уровни интенсивных процессов, чтобы получить то, что вам нужно, но я не уверен, что это подходит для вашей ситуации.

РЕДАКТИРОВАТЬ: Я согласен с Бернардом, поэтому я думаю, что процесс, а не поток, может быть более подходящим, но он просто может не соответствовать вашим целям.

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

В Linux вы можете изменить приоритет планирования потока с помощью nice ().

Проблема в том, что оставлять процессор в режиме ожидания, пока у вас есть работа, ненормально. Обычно вы устанавливаете для фоновой задачи приоритет IDLE, и позволяете ОС распланировать ее все время ЦП, которое не используется интерактивными задачами.

Мне кажется, проблема в сторожевом процессе.

Если ваша фоновая задача связана с процессором, вы хотите, чтобы она занимала все неиспользуемое время процессора для своей задачи.

Может стоит посмотреть на исправление программы сторожевого пса?