Есть ли альтернатива для сна () в C? - PullRequest
14 голосов
/ 05 ноября 2008

В традиционном встроенном программировании мы дадим функцию задержки следующим образом:

for(i=0;i<255;i++)
   for(j=0;j<255;j++);

С точки зрения микропроцессора, работает ли функция sleep ()?

Есть ли альтернатива для функции sleep () в C?

Ответы [ 16 ]

25 голосов
/ 05 ноября 2008

Тип цикла, который вы описываете, называется «ожидание занятости». В реальных операционных системах сон не вызывает напряженного ожидания; он сообщает операционной системе не планировать процесс, пока не закончится период ожидания.

22 голосов
/ 05 ноября 2008

Один из распространенных механизмов - это использование select(), для которого гарантированно истекло время ожидания, и укажите время ожидания в качестве времени ожидания:

// Sleep for 1.5 sec
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 500000;
select(0, NULL, NULL, NULL, &tv);

select() обычно используется для проверки набора файловых дескрипторов и ожидания, пока хотя бы один из них не будет готов выполнить ввод / вывод. Если ни один не готов (или, в этом случае, если fds не указан), он истечет.

Преимущество select() перед циклом занятости состоит в том, что он потребляет очень мало ресурсов во время сна, тогда как цикл занятости монополизирует процессор настолько, насколько позволяет его уровень приоритета.

12 голосов
/ 05 ноября 2008

Альтернативы зависят от того, что вы пытаетесь сделать и на какой ОС вы работаете.

Если вы просто хотите тратить время, это может помочь:

В большинстве систем Unix-типа вы найдете функцию «уснуть», которая более или менее похожа на режим сна с большим разрешением. Будьте осторожны с этим, потому что он обычно не может спать только одну микросекунду.

В некоторых системах Unix-типа системный вызов select может использоваться со всеми нулевыми дескрипторами файлов, чтобы получить довольно точное ожидание в секунду.

В системах Windows у вас есть Sleep, который почти такой же, но занимает несколько миллисекунд.

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

10 голосов
/ 05 ноября 2008

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

То, как вы обычно делаете это, это то, что ваш процессор будет реализовывать какие-то инструкции IDLE или SLEEP, что приведет к временной остановке обработки команд. Внешняя линия прерывания, соединенная со схемой таймера, будет регулярно разбудить процессор, и в этот момент ЦП проверяет, достаточно ли долго он спит, а если нет, то возвращается в режим сна.

//Pseudo code
int start = getTime();
int end = start + sleepTime;

while (getTime() < end) {
       asm("SLEEP");
}

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

7 голосов
/ 05 ноября 2008

Вы говорите о «встроенном программировании» в ОП. Если вы выполняете встроенную работу и вам нужно что-то вроде sleep (), часто доступны аппаратные счетчики / таймеры. Это будет варьироваться от архитектуры к архитектуре, поэтому взгляните на таблицу.

Если вы не делаете встроенную работу, я прошу прощения:)

6 голосов
/ 05 ноября 2008

Больше информации о том, как работает sleep () здесь

Кстати, занятое ожидание не обязательно для любителей - хотя оно и сжигает процессор, который вы можете использовать для каких-то других целей. Если вы используете источник времени, вы ограничены гранулярностью этого источника. НАПРИМЕР. Если у вас есть таймер на 1 мс, и вы хотите 500 мс, у вас есть проблема. Если ваша встроенная система может справиться с тем фактом, что вы будете гудеть в цикле в течение 500 мксек, это может быть приемлемым. И даже если у вас есть таймер с желаемой степенью детализации, вам также необходимо отключить прерывание в это время в нужное время ... затем отправить обработчик прерываний ... и перейти к своему коду. Иногда занятой цикл является наиболее целесообразным решением. Иногда.

6 голосов
/ 05 ноября 2008

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

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

Ранние игры для ПК имели эту проблему - они были созданы для ПК с частотой 4,7 МГц, и, когда появились более быстрые компьютеры, они были неиграбельны.

Наилучший способ, которым может работать «сон», - это чтобы процессор знал, который час в данный момент. Не обязательно фактическое время (7:15 утра), но, по крайней мере, относительное время (8612 секунд с некоторого момента времени).

Таким образом, он может применить дельту к текущему времени и ждать в цикле, пока текущая + дельта не будет достигнута.

Все, что зависит от числа циклов ЦП, по своей сути ненадежно, поскольку ЦП может перейти к другой задаче и оставить ваш цикл зависшим.

Допустим, у вас есть 16-битный порт ввода-вывода с отображением в памяти, который ЦП увеличивает раз в секунду. Предположим также, что он находится в ячейке памяти 0x33 во встроенной системе, где целые числа также 16 бит. Функция, называемая сном, становится примерно такой:

void sleep (unsigned int delay) {
    unsigned int target = peek(0x33) + delay;
    while (peek(0x33) != target);
}

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

5 голосов
/ 05 ноября 2008

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

4 голосов
/ 05 ноября 2008

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

3 голосов
/ 05 ноября 2008

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

poll(0, 0, milliseconds);

для POSIX-совместимых систем. select также работает для окон (для этого у них должен быть собственный API (вероятно, называется Sleep).)

...