十三、隐式网络时间同步
这个粗糙而简单的网络时间同步模块对网络中所有节点的时钟进行同步。
Files
file timesynch.c
A simple time synchronization mechanism.
file timesynch.h
Header file for a simple time synchronization mechanism.
Functions
void timesynch_init (void)
Initialize the timesynch module.
初始化timesynch模块。
rtimer_clock_t timesynch_time (void)
Get the current time-synchronized time.
获取当前时间同步时间。
rtimer_clock_t timesynch_time_to_rtimer (rtimer_clock_t synched_time)
Get the current time-synchronized time,
suitable for use with the rtimer module.
获取当前的时间同步时间,适合与rtimer模块一起使用。
rtimer_clock_t timesynch_rtimer_to_time (rtimer_clock_t rtimer_time)
Get the synchronized equivalent of an rtimer time.
获取与rtimer时间相等的同步时间。
rtimer_clock_t timesynch_offset (void)
Get the current time-synchronized offset from the rtimer clock,
which is used mainly for debugging.
从rtimer时钟获取当前时间同步偏移量,主要用于调试。
int timesynch_authority_level (void)
Get the current authority level of the time-synchronized time.
获取时间同步时间的当前权限级别。
void timesynch_set_authority_level (int level)
Set the authority level of the current time.
设置当前时间的权限级别。
Detailed Description
这个粗糙而简单的网络时间同步模块对网络中所有节点的时钟进行同步。
时间同步是隐式的,因为没有发送显式的时间同步消息:模块依赖于底层的网络设备驱动程序来对所有发出和传入的无线电消息进行时间戳。代码目前只能在Tmote Sky平台和cc2420驱动程序上工作。
每个节点都有一个权限级别,它包含在每个传出包中。如果从具有较高权限(较低权限号)的节点接收到消息,则节点将其时钟调整为与发送节点的时钟一致。
timesynch模块被实现为一个meta-MAC协议,因此对每个传入包调用该模块。
Function Documentation
int timesynch_authority_level ( void )
获取时间同步时间的当前权限级别。
Returns:
时间同步的当前权限级别
此函数返回时间同步时间的当前权限级别。较低权限级别的节点比较高权限级别的节点具有更好的时间概念。权限级别0是最好的,应该由连接到外部“true”时钟源的接收节点使用。
void timesynch_init ( void )
Initialize the timesynch module.
此函数初始化timesynch模块。这个函数不能在rime_init()之前调用。
由main()调用
rtimer_clock_t timesynch_offset ( void )
从主要用于调试的rtimer时钟获取当前时间同步偏移量。
Returns:
rtimer时钟的当前时间同步偏移量
此函数从rtimer arch时钟返回当前时间同步偏移量。这对于调试timesynch模块非常有用。
rtimer_clock_t timesynch_rtimer_to_time (rtimer_clock_t rtimer_time )
获取与rtimer时间相等的同步时间。
Returns:
rtimer时间的同步等价物
此函数返回与(本地)rtimer时间对应的时间同步的等效时间。
void timesynch_set_authority_level ( int level )
Set the authority level of the current time.
由main()调用
Parameters:
level 权限级别
rtimer_clock_t timesynch_time ( void )
获取当前时间同步时间。
Returns:
当前时间同步的时间
这个函数返回当前的时间同步时间。
rtimer_clock_t timesynch_time_to_rtimer (rtimer_clock_t synched_time)
获取当前的时间同步时间,适合与rtimer模块一起使用。
Returns:
当前时间同步的rtimer时间
此函数返回与当前时间同步(全局)时间对应的(本地)rtimer-等效时间。rtimer等效时间用于设置与网络中其他节点同步的rtimer计时器。
十四、protothreads
Proto螺纹是一种轻量级的无堆栈线程,专为内存受限的系统(如深嵌入式系统或传感器网络节点)设计。
Modules
Local continuations
局部延续是实现原生线程的基础。
Protothread semaphores
这个模块实现了在原线程上计数信号量。
Files
file pt.h
Protothreads implementation.
//Initialization
#define PT_INIT(pt)
Initialize a protothread.
初始化一个protothread
Declaration and definition
#define PT_THREAD(name_args)
Declaration of a protothread.
protothread的声明
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function
implementing the protothread.
在实现原型线程的C函数中声明原型线程的开始。
#define PT_END(pt)
Declare the end of a protothread.
声明protothread的结束
Blocked wait
#define PT_WAIT_UNTIL(pt, condition)
Block and wait until condition is true.
堵塞并等到条件为真
#define PT_WAIT_WHILE(pt, cond)
Block and wait while condition is true.
当条件为真是 阻塞并等待
Hierarchical protothreads
#define PT_WAIT_THREAD(pt, thread)
Block and wait until a child protothread completes.
阻止并等待子原型线程完成。
#define PT_SPAWN(pt, child, thread)
Spawn a child protothread and wait until it exits.
生成子线程并等待其退出
Exiting and restarting
#define PT_RESTART(pt)
Restart the protothread.
#define PT_EXIT(pt)
Exit the protothread.
Calling a protothread
#define PT_SCHEDULE(f)
Schedule a protothread.
Yielding from a protothread
#define PT_YIELD(pt)
Yield from the current protothread.
放弃当前的protothread
#define PT_YIELD_UNTIL(pt, cond)
Yield from the protothread until a condition occurs.
当条件发生时放弃
Detailed Description
原线程是一种轻量级无堆栈线程,设计用于内存受限的系统,如深度嵌入式系统或传感器网络节点。
原生线程为c语言中实现的事件驱动系统提供了线性代码执行。原生线程可以使用RTOS,也可以不使用RTOS。
原线程是一种非常轻量级的无堆栈类型的线程,它在事件驱动的系统上提供一个阻塞上下文,没有每个线程堆栈的开销。原线程的目的是在没有复杂状态机或完全多线程的情况下实现连续的控制流。原线程在C函数中提供条件阻塞。
与纯粹的事件驱动方法相比,原生线程的优点是提供了一个顺序的代码结构,允许阻塞函数。在纯事件驱动的系统中,必须通过手动将函数分成两部分来实现阻塞——一段用于阻塞调用之前的代码,另一段用于阻塞调用之后的代码。这使得很难使用诸如if()条件语句和while()循环之类的控制结构。
原生线程相对于普通线程的优势在于,原生线程不需要单独的堆栈。在内存受限的系统中,分配多个堆栈的开销可能会消耗大量可用内存。相反,每个原型线程只需要2到12字节的状态,这取决于架构。
Note:
由于原生线程不会在阻塞调用期间保存堆栈上下文,所以原生线程阻塞时不会保留局部变量。这意味着在使用局部变量时要格外小心——如果有疑问,不要在原生线程中使用局部变量!
Main features:
没有机器特定的代码-原型线程库是纯C
不使用容易出错的函数,如longjmp()
非常小的内存开销——每个原线程只有两个字节
可以使用或不使用操作系统
提供不完全多线程或堆栈切换的阻塞等待
示例应用程序:
Memory constrained systems
Event-driven protocol stacks
Deeply embedded systems
Sensor network nodes
protothreads API包含四个基本操作:初始化:PT_INIT()、执行:PT_BEGIN()、条件阻塞:PT_WAIT_UNTIL()和退出:PT_END()。在这些之上,构建了两个方便的函数:反向条件阻塞:PT_WAIT_WHILE()和原线程阻塞:PT_WAIT_THREAD()。
Proto螺纹是一个非常轻量级的、无堆栈的线程,它在事件驱动的系统之上提供阻塞上下文,而不需要每个线程堆栈的开销。原线程的目的是在不使用复杂状态机或完全多线程的情况下实现控制的顺序流。Proto线程在C函数中提供条件阻塞。
在内存受限的系统中,例如深嵌入式系统,传统的多线程可能会产生太大的内存开销。在传统的多线程处理中,每个线程都需要自己的堆栈,这通常是过度配置的.堆栈可以使用大部分可用内存。
与普通线程相比,原生线程的主要优点是,它非常轻量级:一个原型线程不需要自己的堆栈。相反,所有的原型线程都运行在同一个堆栈上,上下文切换是通过堆栈回绕来完成的。这在内存受限的系统中是有利的,在这种系统中,线程的堆栈可能使用可用内存的很大一部分。每个原型线程只需要两个字节的内存。此外,原型线程是用纯C实现的,不需要任何特定于机器的汇编程序代码.
一个原型线程在单个C函数中运行,不能跨越其他函数。原型线程可以调用普通的C函数,但不能在被调用的函数内阻塞。相反,在嵌套函数调用中阻塞是通过为每个潜在的阻塞函数生成一个单独的原型线程来实现的。这种方法的优点是阻塞是显式的:程序员确切地知道哪个函数阻塞了哪个函数,哪个函数具有永不阻塞的功能。
原线程类似于不对称的协同例程。主要区别在于,对于每个共例程,共例程使用一个单独的堆栈,而原型线程则是无堆栈的。与原型线程最相似的机制是Python生成器。这些也是无堆栈的构造,但目的不同。Proto线程在C函数中提供阻塞上下文,而Python生成器则从生成器函数中提供多个退出点。
局部变量
注:
因为原型线程不会在阻塞调用中保存堆栈上下文,所以当原型线程阻塞时,局部变量不会被保留。这意味着局部变量应该非常小心地使用-如果有疑问,不要在原型中使用局部变量!
排程
一个原型线程是通过对运行该原型线程的函数的重复调用来驱动的。每次调用函数时,原型线程都会运行到阻塞或退出为止。因此,使用原型线程的应用程序完成了对原型线程的调度。
实施
使用局部延续…本地延续表示程序中特定位置的当前执行状态,但不提供任何调用历史记录或局部变量。可以在特定函数中设置本地延续,以捕获函数的状态。在设置了本地延续之后,可以恢复该函数的状态,以便在设置本地延续时恢复该函数的状态。
本地延续可以通过多种方式实现:
通过使用特定于机器的汇编程序代码,
使用标准C结构,或
通过使用编译器扩展。
第一种方法是保存和恢复处理器状态,但堆栈指针除外,每个原型线程需要16到32字节的内存。所需的确切内存量取决于体系结构。
标准C实现每个原型线程只需要两个字节的状态,并以一种与Duff的设备类似的不明显的方式使用C Switch()语句。然而,这个实现对使用原型线程的代码施加了一个轻微的限制,因为代码本身不能使用Switch()语句。
某些编译器具有C扩展,可用于实现原型线程。GCC支持可用于此目的标签指针。使用此实现,每个原型线程需要4字节的RAM。
Define Documentation
#define PT_BEGIN ( pt )
在实现原型线程的C函数中声明原型线程的开始。
此宏用于声明原型线程的起始点。它应该放在运行原生线程的函数的开始处。每次调度原型线程时,PT_BEGIN()调用上面的所有C语句都将执行。
Parameters:
pt 指向原线程控制结构的指针。
#define PT_END ( pt )
Declare the end of a protothread.
此宏用于声明原线程结束。它必须总是与匹配的PT_BEGIN()宏一起使用。
Parameters:
pt 指向原线程控制结构的指针。
#define PT_EXIT ( pt )
Exit the protothread.
这个宏导致原线程退出。如果原线程是由另一个原线程派生的,那么父原线程将被解除阻塞并继续运行。
Parameters:
pt 指向原线程控制结构的指针。
#define PT_INIT ( pt )
Initialize a protothread.
由process_start(), and tr1001_init()调用
初始化一个protothread。初始化必须在执行原型线程之前完成。
Parameters:
pt 指向原线程控制结构的指针。
#define PT_RESTART ( pt )
Restart the protothread.
这个宏将阻塞并导致正在运行的原线程在PT_BEGIN()调用的位置重新启动执行。
Parameters:
pt 指向原线程控制结构的指针。
#define PT_SCHEDULE ( f )
Schedule a protothread.
这个函数调度一个原型线程。如果原生线程正在运行,函数的返回值为非零;如果原生线程已经退出,函数的返回值为零。
Parameters:
f 调用C函数实现要调度的原生线程
#define PT_SPAWN ( pt,
child,
thread
)
生成一个子原生线程并等待它退出。
该宏生成一个子原生线程,并等待它退出。宏只能在原型线程中使用
Parameters:
pt 指向原线程控制结构的指针。
child 指向子原生线程的控制结构的指针。
thread 带有参数的子原生线程
#define PT_THREAD ( name_args )
Declaration of a protothread.
这个宏用于声明一个原生线程。所有的原生线程都必须用这个宏声明。
Parameters:
name_args 实现原型线程的C函数的名称和参数。
#define PT_WAIT_THREAD ( pt,
thread
)
阻塞并等待,直到一个子原生线程完成。
这个宏调度一个子原线程。当前原生线程将阻塞,直到子原生线程完成。
Note:
在使用这个函数之前,必须使用PT_INIT()函数手动初始化子原生线程。
Parameters:
pt 指向原线程控制结构的指针。
thread 带有参数的子原生线程
#define PT_WAIT_UNTIL ( pt,
condition
)
阻塞并等待,直到条件为真。
此宏将阻塞原线程,直到指定的条件为真。
Parameters:
pt 指向原线程控制结构的指针。
condition 条件
#define PT_WAIT_WHILE ( pt,
cond
)
当条件为真时,阻塞和等待。
当条件为真时,此函数阻塞并等待。看到PT_WAIT_UNTIL ()。
Parameters:
pt 指向原线程控制结构的指针。
cond 条件
#define PT_YIELD ( pt )
Yield from the current protothread.
此函数将放弃原型线程,从而允许在系统中进行其他处理。
Parameters:
pt 指向原线程控制结构的指针。
#define PT_YIELD_UNTIL ( pt,
cond
)
带有条件的
Parameters:
pt 指向原线程控制结构的指针。
cond 测试条件
这个函数将生成原型线程,直到指定的条件计算为true。