今天我们将插入一篇关于底层软件的文章,名为“【硬件篇】vcu软件接口原理”的更新工作仍在进行中,预计将超过10篇,敬请期待。今天我们将探讨一种事件驱动模型“protothreads”,由瑞典sics的adam dunkels开发,并在contiki os中使用。这款模型非常适合资源受限的嵌入式系统,我也曾在某个项目中使用过,深感其妙,愿与大家分享。文中所述可能未尽详尽,欢迎各位指出不足之处。
protothreads简介
任务栈:
protothreads是一种轻量级的线程模型,其编程风格类似于Windows中的线程,但更倾向于无线程编程。在操作系统中,每个线程都有独立的任务栈,而protothreads的各个线程共享同一个任务栈,从而减少了RAM的使用。
上下文切换:
在protothreads编程模型中,任务本质上是函数,函数之间协同工作,因此也被称为“协程(coroutine)”。上下文切换与操作系统中的不同,操作系统由OS管理上下文切换,而在protothreads模型中,通过yield方式保存现场并转移运行权。
任务阻塞:
protothreads虽然提供了在各自线程内条件阻塞的机制,但对于在该线程内调用的其他函数,则无法阻塞其运行。因此,如果要在线程内调用耗时较长的函数,为确保各个线程的实时性,需要将这些函数进一步分解为更小的函数,分步执行。protothreads的阻塞本质上是函数返回,且只能在程序员指定的位置进行阻塞。
代码分析
protothreads包含5个头文件,是的,你没看错,是头文件,意味着没有C文件,整个模型是通过宏实现的。下表简单描述了这5个头文件的主要内容。
使用switch语句实现的协程基础
lc.h
用于选择GCC语法还是switch语句实现
pt.h
基于lc.h实现协程API
pt-sem.h
协程间通信(信号量)的实现
主要API包含在pt.h中,以下介绍一些常用的API:
协程初始化代码:#define PT_INIT(pt) LC_INIT((pt)->lc)
解释:初始化一个协程,实际上是初始化状态变量(pt)->lc,类似于MBD模型开发中的各个StateFlow状态;
协程入口代码:
#define PT_BEGIN(pt) \
{ char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)
解释:协程的入口,PT_YIELD_FLAG =1,表示不让出运行权,PT_YIELD_FLAG =0表示让出运行权,LC_RESUME就是跳转到上一次让出运行权的位置继续运行,本质上是switch跳转到相应的case。
协程的退出口代码:
#define PT_END(pt) \
LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
PT_INIT(pt); return PT_ENDED; }
解释:协程的退出口,到此一个协程结束,内容就是清除标志和上下文状态。
协程条件阻塞1代码:
#define PT_WAIT_UNTIL(pt, condition)\
do {\
LC_SET((pt)->lc);\
if(!(condition)) {\
return PT_WAITING;\
}\
} while(0)
解释:协程条件阻塞,阻塞的本质是让出CPU运行权,首先记录下当前的状态(LC_SET((pt)->lc)),以便下一次恢复,保存现场后再判断条件,如果condition为真,则继续往下运行,如果condition为假,直接return返回函数状态PT_WAITING,让出运行权,保持阻塞状态。所以可以这样理解:直到condition条件成立才继续执行,否则继续等待。
协程条件阻塞2代码:
#define PT_WAIT_WHILE(pt,condition) \
PT_WAIT_UNTIL((pt), !(condition))
解释:类似PT_WAIT_UNTIL,只是condition的条件取反。可以这样理解:当condition条件成立时继续等待,否则继续执行。
协程退出代码:
#define PT_EXIT(pt)\
do {\
PT_INIT(pt);\
return PT_EXITED;\
} while(0)
解释:任务后面的代码不执行,初始化状态变量,然后直接退出重新执行。
协程无条件让出运行权代码:
#define PT_YIELD(pt)\
do {\
PT_YIELD_FLAG = 0;\
LC_SET((pt)->lc);\
if(PT_YIELD_FLAG == 0) {\
return PT_YIELDED;\
}\
} while(0)
解释:协程运行权无条件让出一次,让出前,先记录下当前的状态(LC_SET((pt)->lc)),以便下一次恢复,保存现场后,立即让出运行权,本质上是函数return。
协程有条件让出运行权代码:
#define PT_YIELD_UNTIL(pt,condition)\
do {\
PT_YIELD_FLAG = 0;\
LC_SET((pt)->lc);\
if((PT_YIELD_FLAG == 0) || !(condition)) {\
return PT_YIELDED;\
}\
} while(0)
解释:比PT_YIELD(pt)多了一个条件,协程运行权首先无条件让出一次,这是通过PT_YIELD_FLAG来实现的,第二次运行时,再判断条件condition,如果条件为真,继续执行,如果条件为假,则立即让出运行权继续阻塞。
实例
上面介绍了常用API,下面我们看一个实例:
上面的代码就不多解释了,注释已经写得很详细了,唯一需要解释的是这个宏“PT_WAIT_MS”,这是我通过PT_WAIT_UNTIL扩展出来的API,并结合系统Tick实现了延时功能。如果大家熟悉使用后,也可以利用基础的API去扩展自己的功能API。
大家不难发现,相对于使用状态机去实现同样的功能,使用protothreads能够节省很多行代码,而且易于阅读,编程思路和效率也得到提高。
以上就是今天你要来点 protoThread么?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号