2024年Go最全VxWorks几种常用的延时方法_vxworks sleep函数(1),总结2024年180道Golang岗面试题

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

sleep/nanosleep

sleep() 和nanosleep() 是VxWorks提供的延时函数接口,sleep以秒为单位,nanosleep提供更精确的延时,传参是时钟的结构体,参数可以精确到ns,但实际上只能做到大于或等于这个时间。因为sleep或nanosleep函数延时的时间基准仍是tick,调用此函数的任务处于任务延时状态,这些点与taskDelay() 一致。不同的地方是,taskDelay() 是用于任务调度,taskDelay(0)有他自身的含义,sleep(0) 是没有意义的。前面提过,taskDelay(n) 延时时间(n-1) tick ~ n tick,而sleep/nanosleep保证实际延时时间大于或等于设定的时间参数。这一点我们可以通过编写一个测试程序试验证明。代码如下:

void testTimer(int sec,int nsec)  // 测试函数,输入参数为秒和纳秒
{
	struct timespec tm;			// 声明一个时钟结构体,包括秒和纳秒成员
	tm.tv_sec = sec;           // 根据传参赋值
	tm.tv_nsec = nsec;
	nanosleep(&tm,NULL); 	// 执行延时程序
}

在tornado的windshell环境下执行该函数和输出结果如下:

-> sp testTimer,0,1000*1000*16; i
  NAME        ENTRY       TID    PRI   STATUS      PC       SP     ERRNO  DELAY
---------- ------------ -------- --- ---------- -------- -------- ------- -----
tExcTask   _excTask      2318d10   0 PEND         412cd8  2318c14       0     0
tLogTask   _logTask      23131e0   0 PEND         412cd8  23130e4       0     0
tWdbTask   _wdbTask      230e920   3 READY        412cd8  230e7c8       0     0
s2u24      _testTimer    23092b8 100 DELAY        412cd8  23091b4       0     1
value = 0 = 0x0
-> sp testTimer,0,1; i
  NAME        ENTRY       TID    PRI   STATUS      PC       SP     ERRNO  DELAY
---------- ------------ -------- --- ---------- -------- -------- ------- -----
tExcTask   _excTask      2318d10   0 PEND         412cd8  2318c14       0     0
tLogTask   _logTask      23131e0   0 PEND         412cd8  23130e4       0     0
tWdbTask   _wdbTask      230e920   3 READY        412cd8  230e7c8       0     0
s2u25      _testTimer    23092b8 100 DELAY        412cd8  23091b4       0     1
value = 0 = 0x0

可见延时1ns和16ms的结果都是一样的,都相当于taskDelay(1)。

高精度时钟sysTimeStamp

sysTimeStamp()也称作时间戳,是通过系统时钟实现的,刚开始也觉得费解,系统时钟的定时周期就是tick,怎么实现高精度时钟呢?通过走读BSP底层代码发现,sysTimeStamp其实是通过读取该定时器的当前计数值来获取高精度的定时。通过sysTimestampFreq)函数可以得到系统时间戳的频率,它往往反映的是CPU定时器的基准频率。当然如此高的分辨率只能是一个理想值,对于不同的系统不一定都能实现。毕竟该时间戳的实现方式就有一个致命的弱点:通过查询方式。系统时钟定时中断是以tick为单位的,进一步提高分辨率读取定时器计数值(CPU的一个特殊功能寄存器),只能是查询方式实现。如下代码示例。

void msDelay( int ms )
{  
int  t,  t1,  t2;
t1  =  sysTimestamp();     // 记录上一轮时间戳
do
{
t = 0;                 //计数清零
     	while(t <sysTimestampFreq()/1000) // 时间戳小于1ms
{
    		t2 = sysTimestamp();           // 读取当前时间戳
    		if( t2>t1)  t += (t2-t1);          // 根据前后时间戳比较算出经历时间
		else t+=t2; // 发生定时中断清零,应该为t+=(t2+计数最大值-t1),这里简化计算
     		t1 = t2;       // 当前时间戳保存到下一轮计算
     	}
}while(ms--)        // 循环ms次
}

这种方式定时比较占用系统资源,但是能方便实现并只适用于短时间的定时。为确保定时准确,应该在锁定中断情况下调用sysTimestamp,否则应该考虑使用sysTimestampLock函数。

辅助时钟

辅助时钟是利用目标板上CPU的另一个定时器(除了系统时钟之外)中断实现的,它可以灵活配置实现高分辨率的定时,而且容易实现ms级甚至us级定时。VxWorks也提供一系列与系统时钟相同的操作接口,用户可以方便挂接自己的中断处理函数,时钟分辨率的高低取决于硬件定时器的精度和用户中断函数的长短。要将辅助时钟作为精确的延时机制(比如毫秒级延时),我们可以通过这种方式实现。初始化程序先调用SysAuxClkRateSet()函数设置辅助时钟中断周期为1ms(一般在config.h文件中对中断频率作了限定,在AUX_CLK_RATE_MIN和AUX_CLK_RATE_MAX之间,如果需要可以对此宏定义修改),通过SysAuxClkConnect() 将用户处理函数连接到辅助时钟中断上,用户处理函数可以为SemGive(semTimer)释放一个同步信号量。编写一个msDelay(int ms)作为其他任务调用接口,函数代码如下:

void msDelay(int ms)
{
	int i;
	sysAuxClkEnable();    //启动辅助定时器
	for(i=0;i<ms;i++)      //循环ms次
		semTake(semTimer); //等待定时中断释放信号量
sysAuxClkDisable(); //关闭辅助定时器
}

这种方式能实现十分精确的定时,调用延时的任务处于任务阻塞状态。但是使用上任存在缺陷,不能实现多个任务同时调用,并且需要CPU的一个时钟资源,如果没有多余的时钟,这一方法就不能实现。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aaFwDVNA-1636160296577)(https://www.vxworks.net/images/app/timer-spy.jpg)]

另外需要注意一点:Tornado的调试工具Browser ->Spy Chart的实现原理是利用辅助定时器产生中断,并记录当前被中断的任务,抽样数据反映各任务CPU占用率的情况。因此如果调试程序中使用了辅助定时器,使用Spy Chart时,定时处理函数会被重新挂接,原有定时挂接的程序将得不到进行。反过来,如果在Spy Chart运行之后挂接辅助定时处理函数,Spy Chart的运行将出现问题。试验发现,运行Spy Chart后重现挂接辅助定时处理函数,Spy Chart即使选中自动刷新,各任务状态也不会更新,如图2所示。

VxWorks提供的定时接口(不一定专门用于定时,可以间接实现)远不只这些,具体使用哪种方式,应根据其精度要求,资源状态和优先级要求而定。


后面介绍一下重要函数的使用方法

taskDelay( )

NAME

*taskDelay*( ) - delay a task from executing

SYNOPSIS
STATUS taskDelay
    (
    int ticks /* number of ticks to delay task */
    )

DESCRIPTION

This routine causes the calling task to relinquish the CPU for the duration specified (in ticks). This is commonly referred to as manual rescheduling, but it is also useful when waiting for some external condition that does not have an interrupt associated with it.

If the calling task receives a signal that is not being blocked or ignored, *taskDelay*( ) returns ERROR and sets errno to EINTR after the signal handler is run.

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 29
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值