20191012 (22) RT-Thread 线程间通信

目的

1 了解除了全局变量之外更加安全的通信方式


正文

1 邮箱
特点:开销低,效率高,非堵塞,可用于中断
一个邮件大小是 4 个字节针对 32 bit处理系统,用于存储一个字节的大小

对于收 / 发线程而言,可以选择挂起等待或则直接返回,直到由邮箱唤醒

rt_mailbox 对象从 rt_ipc_object 中派生,由 IPC 容器所管理
邮箱控制块是操作系统用于管理邮箱的数据结构 rt_mailbox_t

struct rt_mailbox
{ 
    struct rt_ipc_object parent; rt_uint32_t* msg_pool; /* 邮箱缓冲区的开始地址 */ 
    rt_uint16_t size; /* 邮箱缓冲区的大小 */ 
    rt_uint16_t entry; /* 邮箱中邮件的数目 */ 
    rt_uint16_t in_offset, out_offset; /* 邮箱缓冲的进出指针 */ 
    rt_list_t suspend_sender_thread; /* 发送线程的挂起等待队列 */ 
}; 
typedef struct rt_mailbox* rt_mailbox_t;

结构部分依旧
控制方式与之前一样

创建/初始化 rt_mb_create/init()
获取 rt_mb_send/send_wait()
释放 rt_mb_recv()
删除/脱离 rt_mb_delete/detach()

特别说明: 邮件进入方式
 RT_IPC_FLAG_FIFO 先入先出
RT_IPC_FLAG_PRIO 优先级模式

举例:
就像电子邮箱,理论上应该只有一个拥有者(读取权限),其它线程只能够向目标邮箱发送数据,仅此而已


2 消息队列
特点:邮箱的拓展可以接收串口不定长数据,能够用于中断;
异步,FIFO 原则

控制块 rt_mq_t / rt_messagequeue

struct rt_messagequeue 
{ 
    struct rt_ipc_object parent; void* msg_pool; /* 指向存放消息的缓冲区的指针 */ 
    rt_uint16_t msg_size; /* 每个消息的长度 */ 
    rt_uint16_t max_msgs; /* 最大能够容纳的消息数 */ 
    rt_uint16_t entry; /* 队列中已有的消息数 */ 
    void* msg_queue_head; /* 消息链表头 */ 
    void* msg_queue_tail; /* 消息链表尾 */ 
    void* msg_queue_free; /* 空闲消息链表 */ 
    rt_list_t suspend_sender_thread; /* 发送线程的挂起等待队列 */ 
}; 
typedef struct rt_messagequeue* rt_mq_t;

控制方式与之前一样

创建/初始化 rt_mq_create/init()
获取 rt_mq_send/urgent()/send_wait()
释放 rt_mq_recv()
删除/脱离 rt_mq_delete/detach()

特别说明: 邮件进入方式
 RT_IPC_FLAG_FIFO 先入先出
RT_IPC_FLAG_PRIO 优先级模式

rt_mq_send / rt_mq_send_wait 两种
rt_mq_urgetn() 发送紧急消息是将消息直接插入消息队列的头部

应用:
消息队列可以应用于发送不定长消息的场合,包括线程与线程间的消息交换,以及中断服务例程中给线程发送消息(中断服务例程不能接收消息)


3 信号
特点:采用 linux 消息机制使用异步,POSIX 标准定义 sigset_t 信号集 (RT-Thread 中是 unsigned long)

应用程序可用的 SIGUSR1(10) 和 SIGUSR2(12)

本质:软中断,这就意味着信号被接收到并处理的时间是无法确定的,线程之间可以互相通过调用 rt_thread_kill() 发送软中断信号

处理方法:
1 中断:就是指定处理函数
2 忽略信号
3 保留信号系统的默认值

控制方式与之前一样

安装 rt_signal_install()
堵塞/接触堵塞 rt_signal_mask() / unmask()
发送 rt_thread_kill()
等待 rt_signal_wait()

rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t[] handler);
参数 描述
signo 信号值(只有 SIGUSR1 和 SIGUSR2 是开放给用户使用的)
handler 设置对信号值的处理方式

1 安装信号,就是建立线程和某一信号的映射关系

1)类似中断的处理方式,参数指向当信号发生时用户自定义的处理函数,由该函数来处理。
2)参数设为 SIG_IGN,忽略某个信号,对该信号不做任何处理,就像未发生过一样。
3)参数设为 SIG_DFL,系统会调用默认的处理函数_signal_default_handler()。

2 判断什么信号要被传递
void rt_signal_mask(int signo);
//被屏蔽的信号就不会传递给安装此信号的线程,不会引发中断

void rt_signal_unmask(int signo);
//接触屏蔽的信号

3 通知信号 / 等待消息
int rt_thread_kill(rt_thread_t tid, int sig);
int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t[] *si, rt_int32_t timeout);

发布了120 篇原创文章 · 获赞 27 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_24890953/article/details/102496661