Есть поток, мне нужно задержать процедуру (Updatedann) на 5 милисек.
procedure TDRThread.Execute;
begin
index:=1;
//Запускаю бесконечный цикл
while index>0 do
begin
Synchronize(Updatedann);
sleep(5);
if terminated then exit; //Если поток остановлен, то выйти,
end;
end;
А на самом деле процедура (Updatedann) выполняется только через 15 мсек.
Если вообще убрать sleep, то процедура (Updatedann) выполняется за 0.16 милисек ~(примерно, очень быстро).
Как сделать что бы процедура выполнялась через каждые 5 милисек?
Re: Как заменить sleep в потоке? чтобы получить задержку 5 м
Rius, спасибо огромное за ответ, только я не могу понять, можешь подробнее описать, половина операторов не знаю, к моиму примеру можешь написать? Буду очень благодарен.
Re[3]: Как заменить sleep в потоке? чтобы получить задержку
D>Rius, спасибо огромное за ответ, только я не могу понять, можешь подробнее описать, половина операторов не знаю, к моиму примеру можешь написать? Буду очень благодарен. Я бы хотел ответ на делфи...
Re[4]: Как заменить sleep в потоке? чтобы получить задержку
Здравствуйте, Dasverd, Вы писали:
D>>Rius, спасибо огромное за ответ, только я не могу понять, можешь подробнее описать, половина операторов не знаю, к моиму примеру можешь написать? Буду очень благодарен. Я бы хотел ответ на делфи...
1) Этот метод, хотя и даст более-менее точную задержку, но загрузит процессор (по крайней мере одно ядро) на 100%. Зачем вам задержка в 5 мс, чем 15 не устраивает?
2) Поток, который вызывает в цикле Synchronize, не имеет смысла, т.к. Synchronize вызывается в контексте главного потока.
Re[4]: Как заменить sleep в потоке? чтобы получить задержку
Здравствуйте, Dasverd, Вы писали:
D>>Rius, спасибо огромное за ответ, только я не могу понять, можешь подробнее описать, половина операторов не знаю, к моиму примеру можешь написать? Буду очень благодарен. Я бы хотел ответ на делфи...
Здравствуйте, Dasverd, Вы писали:
D>Как сделать что бы процедура выполнялась через каждые 5 милисек?
А что ты будешь делать, если тебя посередине этого кода планировщик потоков остановит? И уж делай слипы/спинлоки/etc или не делай, но управление обратно получишь через столько времени, через сколько дадут. Может, 15 мс, а может и 15 часов
Опиши, зачем такой жесткий интервал и чем грозит его нарушение? Ибо система Windows не является real-time OS, поэтому гарантий о временных интервалах тебе никто не даст.
Re: Как заменить sleep в потоке? чтобы получить задержку 5 м
Здравствуйте, Dasverd, Вы писали:
D>Есть поток, мне нужно задержать процедуру (Updatedann) на 5 милисек.
D>Как сделать что бы процедура выполнялась через каждые 5 милисек?
Корректно и надежно — никак. By design Windows.
With best regards
Pavel Dvorkin
Re: Как заменить sleep в потоке? чтобы получить задержку 5 м
Здравствуйте, Dasverd, Вы писали:
D>Как сделать что бы процедура выполнялась через каждые 5 милисек?
Вы можете получить близкое к желаемому поведение двумя способами.
1) Вместо потока использовать таймер, создаваемый функцией timeSetEvent. Разрешение до 1-й миллисекунды, а коллбэк вызывается в отдельном потоке.
2) Вызвав в начале своего потока timeBeginPeriod(1), а вконце — timeEndPeriod(1)
Оба способа заставят системный таймер чаще генерить прерывания, и как следствие, планировщик будет чаще получать управление, а значит и сможет чаще выполнять переключение потоков. Надо учитывать что это воздействует на всю систему, а не только на Ваше приложение, увеличивая нагрузку на процессор, поэтому обязательно вызывайте timeEndPeriod. Также надо учитывать, что полной гарантии это не даёт, точность всё равно будет не слишком высока и к тому-же будет зависить от загруженности системы.
Да, на всякий случай — не пользуйтесь для контроля функцией GetTickCount, этот счётчик слишком редко обновляется. Ориентируйтесь на QueryPerformanceCounter
"Нормальные герои всегда идут в обход!"
Re: Как заменить sleep в потоке? чтобы получить задержку 5 м
Парни, sleep() производит задержку 5 милисекунд, и 1 милисекунду, вот только я, не правильно замерял.
Я замерял время задержки (sleep), функцией:
var
NewTim, OldTim, VipTim :TDateTime;
Hour, Min, Sec, MSec :Word;
Begin
NewTim:=Now;
// задержка 15 милисекундsleep(15);//(или фукция которую Вы хотите измерить)
OldTim:=Now;
VipTim:=OldTim-NewTim;
DecodeTime(VipTim, Hour, Min, Sec, MSec);
//перевожу в милисекунды
VipTim:=Hour;
VipTim:=VipTim*3600;
VipTim:=VipTim+Min*60;
VipTim:=VipTim+Sec;
VipTim:=VipTim*1000+MSec;
ShowMessage('Время выполнения фукции = '+floattostr(VipTim)+' милисек');
End;
Оказывается таким способом можно считать время выполнения функции, но если функция выполняется быстрее 15 милисекунд, то бесмыссленно.
Вот результаты:
при sleep(15);
Будет выводится сообщение: (Время выполнения фукции = ~ 15 милисек)
при sleep(5);
Будет выводится сообщение: (Время выполнения фукции = ~15 милисек)
Более точные замеры можно производить следующем способом:
С помощью функций ( QueryPerformanceFrequency, QueryPerformanceCounter)
QueryPerformanceCounter — функция Win32 API.
QueryPerformanceFrequency — возвращает частоту счётчика count/sec.
QueryPerformanceCounter — возвращает текущее значение счетчика с высоким разрешением производительности.
var
Ctr1, Ctr2, Freq,Overhead: int64;
R: extended;
Begin
QueryPerformanceFrequency(Freq);
QueryPerformanceCounter(Ctr1);
QueryPerformanceCounter(Ctr2);
Overhead := Ctr2 - Ctr1;
QueryPerformanceCounter(Ctr1);
//здесь Ваша функция или процедура которую Вы хотите измерить
// допустим задержка sleep(5);
sleep(5);
QueryPerformanceCounter(Ctr2);
R := ((Ctr2 - Ctr1) - Overhead) / Freq;
showmessage( 'Ваша функция выполнилась за ' + FloatToStr(R) + ' секунд');
Результат: Ваша функция выполнилась за 0,0049975 секунд
Следовательно, функция sleep(1) производит задержку в 1 милисекунду, только измерять нужно функциями (QueryPerformanceFrequency, QueryPerformanceCounter).
Так же я нашел способ задержки функции в микросекундах:
procedure DelayUS(MicroS:int64); // Ожидание N microSec
var
Frq_Base, Time_memo, Time_now, dif: Int64;
begin
if QueryPerformanceFrequency(Frq_Base) then // Частота ПК
begin
QueryPerformanceCounter(Time_memo); // начальное значение
repeat
QueryPerformanceCounter(Time_now);
dif := ((Time_now - Time_memo) * 1000000) div Frq_Base;
until dif > MicroS;
end;
end;
Begin
DelayUS(4550); // Задержка микросек
End;
Еще раз спасибо, что посоветовали QueryPerformanceCounter().
Re[2]: Как заменить sleep в потоке? чтобы получить задержку
D>Следовательно, функция sleep(1) производит задержку в 1 милисекунду
Значит, у Вас в системе какое-то приложение уже вызвало функцию timeBeginPeriod(1) и не вызвало timeEndPeriod(1). По хорошему за такое надо-бы руки отрывать.