В традиционном встроенном программировании мы дадим такую функцию задержки:
for(i=0;i<255;i++)
for(j=0;j<255;j++);
В микропроцессорном режиме это работает как функция sleep()?
Есть ли альтернатива для функции sleep() в C?
В традиционном встроенном программировании мы дадим такую функцию задержки:
for(i=0;i<255;i++)
for(j=0;j<255;j++);
В микропроцессорном режиме это работает как функция sleep()?
Есть ли альтернатива для функции sleep() в C?
Альтернативы зависят от того, что вы пытаетесь сделать и от какой ОС вы находитесь.
Если вы просто хотите потратить время, то это может помочь:
В большинстве систем типа unix вы найдете функцию "usleep", которая более или менее похожа на сон с большим разрешением. Будьте осторожны с этим, потому что он обычно не может спать всего за одну микросекунду.
В некоторых системах типа unix системный вызов select может использоваться со всеми нумерами дескрипторов файлов, чтобы получить довольно точный подсчет секунд.
В системах Windows у вас есть Сон, который почти такой же, но занимает несколько миллисекунд.
В многозадачной операционной системе функция sleep иногда может быть задана как параметр. Обычно это приводит к тому, что функция отказывается от времени, но перепланируется немедленно, если никакая другая задача не готова к запуску.
Тип цикла, который вы описываете, называется "ожиданным ожиданием". В реальных операционных системах сон не вызывает ожидание; он сообщает операционной системе не планировать процесс до истечения периода ожидания.
Одним из распространенных механизмов является использование 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()
по циклу занятости состоит в том, что он потребляет очень мало ресурсов во время сна, а цикл занятости монополизирует процессор настолько, насколько это разрешено его уровнем приоритета.
Вы не использовали бы код, который вы опубликовали, чтобы спать во встроенной системе. Хороший компилятор полностью удалит его, и даже если ваш компилятор не удалит его, он будет субоптимальным, так как запуск процессора в жестком цикле будет сжигать мощность, что является проблемой для встроенной системы. Даже системы, не работающие на батарее, заботятся об энергопотреблении, поскольку более низкая потребляемая мощность означает более дешевые источники питания и охлаждение.
Как вы обычно это делаете, ваш процессор будет выполнять какие-то инструкции IDLE или SLEEP, которые заставят его временно прекратить обработку команд. Внешняя линия прерывания, подключенная к цепи таймера, пробуждает процессор обратно с регулярными интервалами и указывает, что процессор проверяет, достаточно ли он спал достаточно долго, а если нет, он снова возвращается в режим сна.
//Pseudo code
int start = getTime();
int end = start + sleepTime;
while (getTime() < end) {
asm("SLEEP");
}
Точные данные зависят от процессора и процессора. Если вы работаете как процесс на ОС, вызов сна обычно просто указывает планировщику приостановить процесс, а затем ядро решает, планировать ли другой процесс или спать CPU. Кроме того, приведенный выше код не будет соответствовать системам реального времени, которые хотят получить гарантии сроков и т.д. В этих случаях вам нужно будет получить время в цикле, узнать продолжительность прерывания времени, чтобы вы знали, можете ли вы справиться без выдувание крайнего срока и возможность перепрограммировать аппаратное обеспечение таймера или ожидание.
Вы говорите о "встроенном программировании" в OP. Если вы выполняете встроенную работу и вам нужно что-то вроде sleep(), часто есть аппаратные счетчики/таймеры. Это будет отличаться от архитектуры к архитектуре, поэтому ознакомьтесь с таблицей данных.
Если вы не выполняете встроенную работу, я приношу свои извинения:)
Если вы используете for-loops, вам лучше знать, что они компилируют, и как долго эти инструкции выполняются с вашей тактовой частотой, и обеспечивают, чтобы процессор выполнял ваши инструкции и ничего больше (это можно сделать во встроенных системах, но это сложно, поскольку он запрещает прерывания).
В противном случае вы не сможете сказать, сколько времени это займет.
У ранних игр для ПК была эта проблема - они были построены для ПК с частотой 4,7 МГц, и, когда быстрые компьютеры пришли, они были невоспроизводимыми.
Лучший способ "сна" может работать, так как ЦП должен знать, в какое время он находится в любой заданной точке. Не обязательно фактическое время (7:15 утра), но по крайней мере относительное время (8612 секунд с некоторого момента времени).
Таким образом, он может применять дельта к текущему времени и ждать в цикле до достижения текущей + дельта.
Все, что полагается на число циклов ЦП, по своей сути ненадежно, поскольку ЦП может перейти к другой задаче и оставить висящий петлю.
Предположим, у вас есть 16-битный порт ввода-вывода с памятью, который процессор наращивает один раз в секунду. Предположим также, что он находится в ячейке памяти 0x33 во встроенной системе, где int также 16 бит. Функция, называемая sleep, становится следующим:
void sleep (unsigned int delay) {
unsigned int target = peek(0x33) + delay;
while (peek(0x33) != target);
}
Вам нужно будет гарантировать, что peek() каждый раз возвращает содержимое памяти (поэтому оптимизация компиляторов не устраняет логику) и что оператор while работает более одного раза в секунду, поэтому вы не пропустите цель, но это операционные проблемы, которые не влияют на концепцию, которую я представляю.
Там больше информации о том, как sleep() работает здесь
Кстати, ожидание ожидания не обязательно для любителей - хотя он и записывает процессор, который вы можете использовать для каких-то других целей. Если вы используете источник времени, вы ограничены детализацией этого источника. НАПРИМЕР. если у вас есть таймер 1 мс, и вы хотите использовать 500 мкс, у вас есть проблема. Если ваша встроенная система может справиться с тем, что вы будете гудеть в цикле на 500 мкс, это может быть приемлемым. И даже если у вас есть таймер с желаемой детализацией, вам также необходимо получить прерывание от таймера в нужное время... затем отправьте обработчик прерываний... затем перейдите к своему коду. Иногда наиболее целесообразным является цикл занятости. Иногда.
Ожидание занятости для любителей даже во встроенной системе, используйте источник в реальном времени.
любой достойный компилятор C, без дополнительной работы, полностью удалит ваш код и задержка исчезнет
sleep фактически взаимодействует с операционной системой, где спящие процессы размещаются вне очереди планирования. Обычно я использую:
poll(0, 0, milliseconds);
для POSIX-совместимых систем. select
также работает для окон (для этого они должны иметь собственный API (вероятно, называемый Sleep
).)
В разделе "Threading in С#" Джозефа Альбахари есть интересное обсуждение этого вопроса. Вы не можете спать менее 1 мс в .Net, но DateTime.Ticks имеет зернистость интервалов в 100-наносекунд (= 0,1 микросекунды). Для управления моим пятиступенчатым шаговым усилителем с ЧПУ мне нужно только приостановить на 10 микросекунд между шаговыми командами. Я использовал микроконтроллер, чтобы делать неприятные петли, но я думаю, что это нормально передать процессор для работы, если у вас есть целая группа в любом случае, остановите поток, когда сможете. По крайней мере, это не всегда будет одно и то же.
#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);
}
Да, он использует некоторые недокументированные функции ядра, но, честно говоря, он намного быстрее, чем большинство предложений, и работает очень хорошо (обратите внимание, что он будет ограничен количеством процессора, например, моя может спать только 500 наносекунд (0,5))
доступен в linux usleep (int microseconds) nanosleep (...) больше точности см. man-страницы для вызова аргументов
В ОС Unix-производной вы, вероятно, планируете вызов сигнала(), и ваш код будет просто блокировать код до тех пор, пока сигнал не будет поднят. Сигналы предназначены для этой цели, и они очень просты и эффективны.
попытка... действительно решить эту проблему, то есть что-то, что работает (не похоже на вышеупомянутые попытки ответа) 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;
}
Я нашел функцию в этом сообщении (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;
}