1、能降低CPU占用就行
只要我的进程不出现在高cpu占用榜单上,不被其他组员锤死就行!
#include <unistd.h> // 引入 usleep()
int main(void)
{
while(1)
{
//没有特殊要求延时最好放到前面,避免忘记
usleep(1000);
//没有精神的干活
;
}
return 0;
}
2、听别人说usleep延时不准,还有没有别的方法?
传说中通过select来间接得到准确延时的方法
#include <stdio.h> // 引入 NULL
#include <sys/time.h> // 引入 struct timeval
void delayUs(long int us)
{
struct timeval tv;
tv.tv_sec = us / 1000000;
tv.tv_usec = us % 1000000;
select(0, NULL, NULL, NULL, &tv);
}
int main(void)
{
while(1)
{
delayUs(1000);
//假装有精神的干活
;
}
return 0;
}
但从我的实际测试结果来看(树莓派4B),usleep和select的延时效果相差不多,他们有一个共同的问题就是实际延时要多几百us,手动矫正一下还是可以用的。后面在其它平台测了一下,准确的说应该是usleep在树莓派里超长发挥了,select还是比较稳定的。
3、严格周期任务
由于干活的内容所花时长不定,导致下一个周期开始时要么提前了一点、要么晚了一点,有没什么办法保证周期固定?比方约好了每天中午12点搬砖,那么周期就是24小时,今天花10个小时把砖搬完,就休息14小时;花13个小时把砖搬完,就休息11个小时。首先要识别当前干活花了多少时间,然后根据时间差进行延时。
#include <stdio.h> // 引入 NULL
#include <sys/time.h> // 引入 struct timeval
// 获取系统tick可以作为us时长参考
long int getTickUs(void)
{
struct timeval tv = {0};
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000u + tv.tv_usec;
}
void delayUs(long int us)
{
struct timeval tv;
tv.tv_sec = us / 1000000;
tv.tv_usec = us % 1000000;
select(0, NULL, NULL, NULL, &tv);
}
// 延时初始化
#define DELAY_INIT \
long int _tick1 = 0, _tick2;
// 检查时差,差多少延时多少
#define DELAY_US(us) \
_tick2 = getTickUs(); \
if (_tick2 >= _tick1 && _tick2 - _tick1 < us)\
delayUs(us - (_tick2 - _tick1)); \
_tick1 = getTickUs();
int main(void)
{
DELAY_INIT;
while(1)
{
DELAY_US(500000);
//随机时长的干活(我也不知道接下来要干多久,总之500ms以内就是了)
;
}
return 0;
}
这种延时的特点就是周期固定,当你不知道接下来的内容会花费多长时间,但又希望周期轮询当前内容时就适合这种延时。
4、严格周期任务 - 改
每种延时都是有误差的,如何用有误差的延时搭建稳定的周期任务?可以利用延时偏大的特点,每次延时目标时差的一半,结束后计算误差,再一半,如此循环多次,即使每次延时都不准确,但最后总能把误差压到最小;另外,循环不可能无限次,应设定一个可接受的误差以结束循环。
#include <stdio.h> // 引入 NULL
#include <sys/time.h> // 引入 struct timeval
// 获取系统tick可以作为us时长参考
long int getTickUs(void)
{
struct timeval tv = {0};
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000u + tv.tv_usec;
}
void delayUs(long int us)
{
struct timeval tv;
tv.tv_sec = us / 1000000;
tv.tv_usec = us % 1000000;
select(0, NULL, NULL, NULL, &tv);
}
// 延时初始化
#define DELAY_INIT2 \
long int _tick = 0, _tickErr;
// 每次延时一半时差,直至延时满us或差值小于err,注意要放在循环开始
#define DELAY_US2(us, err) \
_tickErr = getTickUs() - _tick; \
if (_tickErr >= 0 && us > _tickErr) \
{ \
_tickErr = us - _tickErr; \
if (_tickErr > err) \
{ \
delayUs(_tickErr / 2); \
continue; \
} \
} \
_tick = getTickUs();
int main(void)
{
DELAY_INIT2;
while(1)
{
//目标延时500ms,接受误差50us
DELAY_US2(500000, 50);
//安心的干活
;
}
return 0;
}
这种延时周期性精度高、抗干扰能力强,可以用在对周期和稳定性要求都较高的场景,如音、视频播放,帧数据传输等。