C основной цикл без 100% процессорного времени - PullRequest
19 голосов
/ 03 августа 2009
#include <stdio.h>

int main() {
  while(!DONE) {
    /* check for stuff */
  }
  return 0;
}

В приведенном выше примере кода используется 100% ЦП, пока DONE не станет истинным. Как я могу реализовать программу, которая зацикливается и завершает свою работу только когда ГОТОВО, но не использует 100% ЦП? Современные языки используют что-то вроде App.ProcessMessages или что-то подобное, чтобы на данный момент дать ОС управление, а затем вернуться к циклу.

Я новичок в C, очевидно ... использую последние GCC, Linux и Windows (портативное решение было бы здорово!)

Ответы [ 11 ]

16 голосов
/ 03 августа 2009

Это зависит от того, что вы хотите сделать внутри этого цикла.

Если вы ждете внутри цикла (то есть, если нажата клавиша {сделать что-то}, то ваш механизм будет тратить системные ресурсы, ничего не давая взамен. Более быстрый процессор просто сделает больше свободных циклов. Это можно решить, ожидая событий, а не просто sleep, но предпочтительно событие, которое запускает выполнение чего-то значимого. Например, файловая операция (stdin также является файлом) будет переносимым механизмом. Это уступит место другим приложениям, пока данные не станут доступны. Когда вы станете более В частности, может потребоваться погрузиться в семафоры или сигналы, которые часто зависят от ОС. Уровень абстракции может решить эту проблему.

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

Использование такой функции, как sleep, приведет к уменьшению использования процессора, но ваше приложение будет работать медленнее. Это потребует компромисса между приемлемой производительностью и загрузкой процессора. Максимальная скорость выполнения будет определяться вашим параметром сна, а не скоростью процессора. Кроме того, если проблема связана с питанием (то есть временем работы от батареи), то это потребует от процессора активации (окончания периода ожидания) без выполнения каких-либо работ; то есть другая трата системных ресурсов.

11 голосов
/ 03 августа 2009

У вас есть несколько вариантов:

  1. Используйте sleep (), чтобы заставить процесс периодически приостанавливаться и разрешать другому процессу использовать процессор
  2. Запуск с более низким уровнем приоритета - что заставит ОС назначать меньше процессорного времени
  3. Используйте мьютекс или другой объект синхронизации, чтобы определить, когда работа доступна, что не позволит процессу потреблять процессорное время, если только он фактически не выполняет работу
  4. Если вы получаете работу быстрее, чем можете ее обработать - вам все равно может понадобиться какая-то модель сна / приоритета, чтобы избежать полной загрузки ЦП.

Вариант № 2 может быть сложным в нейтральной платформе / ОС. Лучше всего запустить процесс и изменить его приоритет в среде выполнения.

5 голосов
/ 03 августа 2009

Ваши два варианта - опрос и какое-то уведомление о событии.

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

Другим вариантом является ожидание условного события POSIX, события Windows или чего-то подобного. Мало того, что этот код будет изменен, но тогда «материал, который вы проверяете» должен будет вызвать флаг, чтобы сказать, что это сделано. Это был бы немного менее переносимый код, хотя, вероятно, есть библиотеки для абстрагирования платформы. Но вы получите немедленные результаты к событию и не потратите впустую время процессора на проверку того, чего там нет.

3 голосов
/ 03 августа 2009

Что именно вы проверяете?

Если вы проверяете что-то изменчивое, которое изменяется аппаратно или другим процессом, просто вызовите sleep в вашем цикле.

Если вы ожидаете дескриптор файла или дескриптор сетевого сокета, вы можете использовать select или poll в цикле, чтобы дождаться, пока дескриптор подготовит данные для использования.

2 голосов
/ 03 августа 2009

Если я правильно понял, вы сказали в комментариях, что DONE можно изменить из других тем. Если это так, условные переменные имеют смысл. С pthreads можно было бы сделать:

В теме, которая ждет:

pthread_mutex_lock(&mutex);
while (!DONE) {
     pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);

В других темах при изменении DONE:

pthread_mutex_lock(&mutex);
DONE = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
1 голос
/ 09 июля 2013

Sleep(0); было бы достаточно, я думаю,

1 голос
/ 03 августа 2009

использование

Сон (в миллисекундах)

0 голосов
/ 24 октября 2009

Sleep (0); достаточно

0 голосов
/ 03 августа 2009

В windows вы можете использовать Sleep (int milliseconds), определенный в windows.h.

0 голосов
/ 03 августа 2009

Если я правильно угадываю (я не знаю об этом), эквивалент App.ProcessMessages выполняет блокировку ввода-вывода. И поскольку я не знаю какой-либо реализации C в многозадачной ОС, которая использует опрос, любой стандартный C IO должен быть безопасным.

...