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

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

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

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

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

хорошо, в моей среде настольный компьютер Windows и компилятор turbo c, тогда для среды рабочего стола есть ли альтернатива для sleep ()? (не для встроенных систем)

Manoj Doubts 05.11.2008 08:29

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

Evan Teran 05.11.2008 09:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
14
2
52 426
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

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

есть место и для того, и для другого. Например, ядро ​​Windows KeStallExecutionProcessor занято ожиданием, а KeDelayExecutionThread не занято ожиданием. Бывает ситуация, когда вы хотите подождать без потери контекста, например reset hw -> wait some micro -> do rest of hw init

Ilya 05.11.2008 16:55

Я согласен, что бывают случаи, когда активное ожидание действительно уместно и реализовано в ядре. например, спин-блокировка. Поэтому я полагаю, что мой ответ должен быть таким: «в реальных ОС спящий режим не вызывает как правило активного ожидания». :-)

Chris Jester-Young 06.11.2008 11:25

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

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

Если вы используете циклы 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 выполняется чаще одного раза в секунду, чтобы вы не пропустили цель, но эти это операционные проблемы, которые не влияют на концепцию, которую я представляю.

Я думаю, вам понравится while (peek(0x33) < target);, или у вас будет забавный опыт отладки, когда (по какой-то причине) HW пропускает точное значение, которое вас интересует.

erikkallen 21.04.2010 20:01
Ответ принят как подходящий

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

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

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

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

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

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

Один из распространенных механизмов - использовать 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() перед циклом занятости заключается в том, что он потребляет очень мало ресурсов во время сна, в то время как цикл занятости монополизирует процессор настолько, насколько это разрешено его уровнем приоритета.

Возможно, излишняя инженерия, но я думал, что select () можно прерывать сигналами. Что произойдет, если он прервется через полсекунды?

paxdiablo 05.11.2008 08:11

Хорошая уловка - в этом случае используйте pselect () для маскировки сигналов или создайте свои собственные обработчики сигналов с учетом сна. Спасибо!

Adam Liss 05.11.2008 08:22

Но написано здесь(там нажмите на ожидание ввода-вывода), что select не прерывается. Проблема с select объясняется здесь

Abhishek Gupta 27.12.2012 14:21

В ОС, производной от unix, вы, вероятно, запланировали бы вызов signal (), и ваш код просто заблокировал бы код до тех пор, пока не будет подан сигнал. Сигналы предназначены для этой цели, они очень просты и эффективны.

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

bog 05.11.2008 08:54

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

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

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

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

poll(0, 0, milliseconds);

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

Мы обнаружили ошибку в linux 2.6.11.6, из-за которой в определенных ситуациях опрос приводил к зависанию всей системы. Переключение на select () устранило проблему; не знаю, существует ли он еще в последних ядрах.

Adam Liss 05.11.2008 09:02

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

Я помню некоторые тесты МНОГИХ лет назад, когда определенный исполняемый файл, созданный компилятором, превосходил другие компиляторы на много порядков. Оказалось, что это компилятор, понимающий, что результат цикла больше нигде не используется, поэтому он оптимизировал весь цикл :-).

paxdiablo 05.11.2008 09:40

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

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

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

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

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

Что делать, если конец <начало из-за опрокидывания таймера?

bk1e 05.11.2008 10:23

псевдокод, я могу игнорировать эти детали, предполагая бесконечный размер int ;-)

Louis Gerbarg 05.11.2008 11:24

На странице 20 книги Джозефа Альбахари «Threading in C#» есть интересное обсуждение этого вопроса. Вы не можете спать менее 1 мс в .Net, но DateTime.Ticks имеет гранулярность интервалов в 100 наносекунд (= 0,1 микросекунды). Для управления моим 5-осевым шаговым ЧПУ мне нужно делать паузу всего на 10 микросекунд между шаговыми командами. Я использовал микроконтроллер для выполнения неприятного цикла, но я думаю, что это нормально, передать процессор для работы, если у вас все равно целая куча, остановите поток, когда сможете. По крайней мере, он не всегда будет одним и тем же.

попытка ... действительно решить эту проблему, т.е. что-то, что работает (не как попытки ответа выше) lol

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

// Sleep for both Windows and Linux: 
// Too bad? No one proposed you a solution that works? 
// Since Windows has no select.h nor poll.h, an implementation
// is necessary.
//  
// Solutions on boards are often refered to use either select or poll, but ok, what about C (not c++)?
//
/// implementation of poll is destined in this attempt for windows
/// Ideally, you add this part of code to the header of you *.c file, and it might work through...

#ifdef WIN32
#include <time.h>
#include <sys/time.h>
#include <ws2tcpip.h>
#include <Winsock2.h>
#include <windows.h>
/* winsock doesn't feature poll(), so there is a version implemented
 * in terms of select() in mingw.c. The following definitions
 * are copied from linux man pages. A poll() macro is defined to
 * call the version in mingw.c.
 */
#define POLLIN      0x0001    /* There is data to read */
#define POLLPRI     0x0002    /* There is urgent data to read */
#define POLLOUT     0x0004    /* Writing now will not block */
#define POLLERR     0x0008    /* Error condition */
#define POLLHUP     0x0010    /* Hung up */
#define POLLNVAL    0x0020    /* Invalid request: fd not open */
struct pollfd {
  SOCKET fd;        /* file descriptor */
  short events;     /* requested events */
  short revents;    /* returned events */
};

int mingw_poll (struct pollfd *, unsigned int, int);

#define poll(x, y, z)        mingw_poll(x, y, z)
#endif





int mingw_poll(struct pollfd *fds, unsigned int nfds, int timo)
{
    struct timeval timeout, *toptr;
    fd_set ifds, ofds, efds, *ip, *op;
    int i, rc;

    /* Set up the file-descriptor sets in ifds, ofds and efds. */
    FD_ZERO(&ifds);
    FD_ZERO(&ofds);
    FD_ZERO(&efds);
    for (i = 0, op = ip = 0; i < nfds; ++i) {
    fds[i].revents = 0;
    if (fds[i].events & (POLLIN|POLLPRI)) {
        ip = &ifds;
        FD_SET(fds[i].fd, ip);
    }
    if (fds[i].events & POLLOUT) {
        op = &ofds;
        FD_SET(fds[i].fd, op);
    }
    FD_SET(fds[i].fd, &efds);
    } 

    /* Set up the timeval structure for the timeout parameter */
    if (timo < 0) {
    toptr = 0;
    } else {
    toptr = &timeout;
    timeout.tv_sec = timo / 1000;
    timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000;
    }

#ifdef DEBUG_POLL
    printf("Entering select() sec=%ld usec=%ld ip=%lx op=%lx\n",
           (long)timeout.tv_sec, (long)timeout.tv_usec, (long)ip, (long)op);
#endif
    rc = select(0, ip, op, &efds, toptr);
#ifdef DEBUG_POLL
    printf("Exiting select rc=%d\n", rc);
#endif

    if (rc <= 0)
    return rc;

    if (rc > 0) {
        for (i = 0; i < nfds; ++i) {
            int fd = fds[i].fd;
        if (fds[i].events & (POLLIN|POLLPRI) && FD_ISSET(fd, &ifds))
            fds[i].revents |= POLLIN;
        if (fds[i].events & POLLOUT && FD_ISSET(fd, &ofds))
            fds[i].revents |= POLLOUT;
        if (FD_ISSET(fd, &efds))
            /* Some error was detected ... should be some way to know. */
            fds[i].revents |= POLLHUP;
#ifdef DEBUG_POLL
        printf("%d %d %d revent = %x\n", 
                FD_ISSET(fd, &ifds), FD_ISSET(fd, &ofds), FD_ISSET(fd, &efds), 
                fds[i].revents
        );
#endif
        }
    }
    return rc;
}

Я думаю, что этот ответ не соответствует исходному вопросу. Это больше похоже на кроссплатформенное решение select () и включает опрос. Настоящий спящий режим ОС не вызывает опроса процесса.

Ogre Psalm33 19.09.2013 16:50

Я нашел функцию в этом посте (http://cboard.cprogramming.com/c-programming/111229-how-use-sleep-function.html), и она работает:

#include <stdio.h>
#include <windows.h>

int main()
{
    puts("Hello \n");
    /* in windows.h is declared the Sleep (upper S) function and it takes time in 
miliseconds */
    Sleep(3000);
    puts("World \n");
    return 0;
}
#include <Windows.h>

static NTSTATUS(__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval) = (NTSTATUS(__stdcall*)(BOOL, PLARGE_INTEGER)) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtDelayExecution");

static NTSTATUS(__stdcall *ZwSetTimerResolution)(IN ULONG RequestedResolution, IN BOOLEAN Set, OUT PULONG ActualResolution) = (NTSTATUS(__stdcall*)(ULONG, BOOLEAN, PULONG)) GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwSetTimerResolution");




static void SleepShort(float milliseconds) {
    static bool once = true;
    if (once) {
        ULONG actualResolution;
        ZwSetTimerResolution(1, true, &actualResolution);
        once = false;
    }

    LARGE_INTEGER interval;
    interval.QuadPart = -1 * (int)(milliseconds * 10000.0f);
    NtDelayExecution(false, &interval);
}

доступно в Linux usleep (число микросекунд) nanosleep (...) больше точности см. справочные страницы для вызова аргументов

Другие вопросы по теме