Zephyr内核对象--数据传递对象总结增补

Creative Commons
本作品采用知识共享署名

本文分析数据传递对象传递数据的系统效能。

本文是做为Zephyr内核对–数据传递对象简介的增补篇对所有的数据传进行效能分析。
每种数据传递对象的分析可以参考下面文章
Zephyr内核对象-数据传递之FIFO/LIFO
Zephyr内核对象-数据传递之Stack
Zephyr内核对象-数据传递之Message Queue
Zephyr内核对象-数据传递之邮箱
Zephyr内核对象-数据传递之管道

加锁方式

在数据传递过程中,内存有自旋锁和锁调度两种加锁方式:

自旋锁

本文只考虑单核CPU,在此情况下自旋锁退化为锁中断,我们假定没有配置非延迟中断,因此k_spin_lock将会锁所有的中断。
对应于k_spin_lock,可以使用k_spin_unlock,z_reschedule,z_pend_curr进行解锁

锁调度

k_sched_lock上锁后,不会再发生线程调度(但会响应中断),k_sched_unlock后恢复调度

数据传递方式分析和加锁影响

下面列出不同数据对象传递数据的方式,并列出传递时加锁的方式

queue/fifo/lifo

将数据的内存指针以链表形式管理,指针长度的数据copy

  • queue_insert
    k_spin_lock->链表插入->z_reschedule

  • z_impl_k_queue_get
    k_spin_lock -> 从链表移除 ->k_spin_unlock
    k_spin_lock -> z_pend_curr(无数据等待)

queue/fifo/lifo在传递数据的时候会锁中断,但由于只是链表操作,数据也只有指针长度,对系统效能影响不大。传递的是数据指针,数据0拷贝。

statck

将数据指针存放在堆栈中,指针长度的数据copy

  • z_impl_k_stack_push
    k_spin_lock -> 数据指针入栈 -> z_reschedule
    k_spin_lock -> k_spin_unlock(堆栈满)
  • z_impl_k_stack_pop
    k_spin_lock->数据指针出堆栈->k_spin_unlock
    k_spin_lock -> z_pend_curr(堆栈空,等数据)

在传递数据的时候会锁中断,但由于只是堆栈操作,单位数据也只有指针长度,对系统效能影响不大。传递的是数据指针,数据0拷贝。

消息列队

将消息以ring-buffer形式管理,一次传送copy的大小为消息的长度,消息可以包含所有数据,也可以只包含指向消息数据的指针,传递只copy消息,不copy消息数据指针指向的数据

z_impl_k_msgq_put

k_spin_lock -> copy消息大小->z_reschedule
k_spin_lock-> z_pend_curr (等待发送)
k_spin_lock-> k_spin_unlock(不等待发送)

z_impl_k_msgq_get

k_spin_lock->copy消息大小->z_reschedule
k_spin_lock-> z_pend_curr (等待数据)
k_spin_lock-> k_spin_unlock(不等待数据)

在传递数据的时候会锁中断,会对消息数据进行拷贝,为了减少对系统的影响,定义消息列队的消息时需要控制消息的长度,如果有大数据需要传递,只在消息里面传递数据的指针,传递数据0拷贝。

邮箱

将消息中包含消息数据指针,接收者将copy消息中数据指针指向所有数据,接收完后发送者才会退出。

mbox_message_put

k_spin_lock -> 匹配 ->等待接收copy数据z_pend_curr
k_spin_lock -> z_pend_curr(未匹配,等待发送)
k_spin_lock -> k_spin_unlock(未匹配,不等待发送)

k_mbox_get

k_spin_lock->匹配->k_spin_unlock->copy消息数据->通知copy完成
k_spin_lock-> k_spin_unlock(未匹配,等待接收消息)
k_spin_lock-> k_spin_unlock(未匹配,不等待)

只在匹配时会锁中断,对系统效能影响不大。在传递数据的时必须进行数据拷贝,数据过大需要考虑使用消息队列做0拷贝动作

管道

要发送的所有数据都在管道内,接收者会copy所有管道内的数据

z_pipe_put_internal

k_spin_lock -> 有thread等待读pipe数据->z_sched_lock->k_spin_unlock->copy pipe数据->k_sched_unlock
k_spin_lock -> 无thread等待读pipe数据->k_spin_unlock(不等待发送)
k_spin_lock -> 无thread等待读pipe数据->z_sched_lock->k_spin_unlock->z_sched_unlock_no_reschedule->k_spin_unlock(等待发送)

z_impl_k_pipe_get

k_spin_lock -> 有thread等待写pipe数据->z_sched_lock->k_spin_unlock->copy pipe数据->k_sched_unlock
k_spin_lock -> 无thread等待读pipe数据->k_spin_unlock(不等待接收)
k_spin_lock -> 无thread等待读pipe数据->z_sched_lock->k_spin_unlock->z_sched_unlock_no_reschedule->k_spin_unlock(等待接收)

只在检查pipe时锁中断,对系统效能影响不大,但在传递数据时需要锁调度,且是拷贝所有数据,在拷贝数据期间其它线程均无法打断,如果数据过大会影响系统效能。