xuos-web/docs/doc/kernel/threadcommunication.md

13 KiB
Raw Blame History

线程间通信

XiUOS 的线程间通信使用邮箱、消息队列和信号三种方式。下面将分别介绍。

邮箱

邮箱的工作机制

XiUOS 的每一封邮件大小为4字节也就是一个指针的大小。典型的邮箱应用是线程或中断服务发送一封4字节长度的邮件到邮箱中其他的线程可以从邮箱中接收邮件并进行处理。

当一个线程向邮箱发送邮件时如果邮箱没满就将邮件复制到邮箱中。如果邮箱满了并且超时时间设置为0则返回-XS_EFULL如果超时时间不为0先将该发送线程挂起当邮箱中的邮件被取出空出空间后等待挂起的发送线程被唤醒继续发送。但是如果到达超时时间仍没有空间则返回-XS_EFULL

当一个线程从邮箱中接收邮件时如果邮箱中有邮件就读出该邮件的内容并返回XS_EOK。如果邮箱中没有邮件并且超时设置为0则返回-XS_ETIMEOUT如果超时时间不为0则将该线程挂在邮箱的等待线程中有邮件时唤醒。但是如果到达超时时间仍没有邮件返回-XS_ETIMEOUT

结构体定义和函数接口

邮箱控制块

struct xs_Mailbox
{
    char            name[XS_NAME_MAX];
    xs_uint8        style;

    xs_uint8        sign;

    xs_list_t       link;

    xs_list_t       pend_list;
   
    xs_ubase        *msg_buf;                     
    xs_uint16       size;                    
    xs_uint16       index;                      
    xs_uint16       in_offset;                   
    xs_uint16       out_offset; 
                      
    xs_list_t       pend_sender_list;      
};

typedef struct xs_Mailbox *xs_mailbox_t;
参数 描述
name 邮箱名称
style 线程等待的方式可以取FIFO或PRIO
sign 标记邮箱的创建方式,静态创建或动态创建
link 邮箱存放的列表
pend_list 线程等待队列
msg_buf 邮箱缓冲区开始地址
size 邮箱最大容纳的邮件数
index 邮箱中邮件的索引
in_offset 邮箱缓冲的进指针
out_offset 邮箱缓冲的出指针
pend_sender_list 发送线程的挂起等待队列

函数接口

xs_err_t xs_InitMailbox(xs_mailbox_t mb, 
                        const char*  name, 
                        void*        msgpool, 
                        xs_size_t    size, 
                        xs_uint8     flag);

该函数用于创建一个静态邮箱对象,并将它加入邮箱管理列表中,创建成功返回XS_OK

参数 描述
mb 邮箱对象
name 邮箱名称
msgpool 缓冲区指针
size 邮箱容量
flag 线程等待的方式可以取FIFO或PRIO

xs_err_t xs_DetachMailbox(xs_mailbox_t mb);

该函数用于脱离静态初始化的邮箱对象。该函数唤醒所有挂在该邮箱上的线程,然后将该邮箱从邮箱存放的列表中脱离,返回XS_OK

参数 描述
mb 邮箱对象
xs_mailbox_t xs_CreateMailbox(const char *name, xs_size_t size, xs_uint8 flag);

该函数用于创建一个动态邮箱对象,并将它加入邮箱管理列表中。创建成功则返回XS_OK,创建失败返回XS_NULL

参数 描述
name 邮箱名称
size 邮箱容量
flag 线程等待的方式可以取FIFO或PRIO

xs_err_t xs_DeleteMailbox(xs_mailbox_t mb);

该函数用于删除动态邮箱对象。先唤醒挂在邮箱对象上的所有线程,然后释放该邮箱的使用内存,最后删除邮箱对象。返回XS_OK

参数 描述
mb 邮箱对象

xs_err_t xs_MailboxSendWait(xs_mailbox_t mb, xs_ubase value, xs_int32 timeout);

该函数用于发送邮件。如果邮箱满了并且过了timeout时间仍然没有空位则返回-XS_FULL;否则将邮件存放入邮箱。

参数 描述
mb 邮箱对象
value 邮件内容
timeout 超时时间

xs_err_t xs_MailboxSend(xs_mailbox_t mb, xs_ubase value);

该函数用于发送邮件。与xs_MailboxSendWait唯一不同的地方是,该函数的timeout == 0

参数 描述
mb 邮箱对象
value 邮件内容

xs_err_t xs_MailboxRecv(xs_mailbox_t mb, xs_ubase *value, xs_int32 timeout);

该函数用于接受邮件。

xs_err_t xs_CmdControlMailbox(xs_mailbox_t mb, int cmd, void *arg);

该函数用于获取或设置邮箱的其他属性。目前当cmd == XS_LINKLIST_CMD_RESET时,重新初始化邮箱。

参数 描述
mb 邮箱对象
cmd 需要执行的命令
arg 命令的参数

消息队列

消息队列的工作机制

消息队列能够接收线程或中断产生的不固定长度的消息,并储存到自己的内存空间中。其他线程可以从消息队列中读取相应的消息。当消息队列为空时,挂起读取线程,当有新的消息到达时,唤醒读取线程进行读取。

结构体定义和函数接口

结构体定义

struct xs_MessageQueue
{
    char       name[XS_NAME_MAX];
    xs_uint8 style;

    xs_uint8   sign;


    xs_list_t  link;

    xs_list_t            pend_list;

    void                *msg_buf;                      

    xs_uint16          size;                    
    xs_uint16          max_msgs;                      

    xs_uint16          index;                  

    void                *mq_listhead;              
    void                *mq_listtail;                
    void                *mq_free;           

    xs_list_t            pend_sender_thread;         
};
typedef struct xs_MessageQueue *xs_messagequeue_t;
参数 描述
name 消息队列名称
style 线程等待的方式可以取FIFO或PRIO
sign 标记消息队列的创建方式,静态创建或动态创建
link 消息队列存放的列表
pend_list 线程等待队列
msg_buf 存放消息的缓存区
size 缓存区大小
max_msgs 一条消息的最大长度
index 当前消息数
mq_listhead 消息链表头
mq_listtail 消息链表尾
mq_free 空闲消息链表
pend_sender_thread 发送线程的挂起等待队列

函数接口

xs_err_t xs_InitMessageQueue(xs_messagequeue_t     mq,
                    const char *name,
                    void       *msgpool,
                    xs_size_t   msg_size,
                    xs_size_t   pool_size,
                    xs_uint8  flag)

该函数用于初始化一个静态消息队列,并将它加入消息队列管理列表中。创建成功后返回XS_OK

参数 描述
mq 消息队列对象指针
name 消息队列名称
msgpool 指向存放消息的内存空间的指针
msg_size 一条消息的最大长度
pool_size 存放消息的内存区大小
flag 消息队列采用的等待方式可取FIFO或PRIO

xs_err_t xs_DetachMessageQueue(xs_messagequeue_t mq)

该函数用于将一个静态消息队列从消息队列管理列表中移除。移除成功则返回XS_OK

参数 描述
mq 消息队列对象指针

xs_messagequeue_t xs_CreateMessageQueue(const char *name,
                     xs_size_t   msg_size,
                     xs_size_t   max_msgs,
                     xs_uint8  flag)

该函数用于动态创建一个消息队列,并将消息队列加入消息队列管理列表。

参数 描述
name 消息队列名称
msg_size 缓冲区的大小
max_msgs 一条消息的最大长度
flag 消息队列采用的等待方式可取FIFO或PRIO

xs_err_t xs_DeleteMessageQueue(xs_messagequeue_t mq)

该函数用于将由xs_CreateMessageQueue创建的消息队列从消息队列管理列表中删除。

参数 描述
mq 消息队列对象指针

xs_err_t xs_MessageQueueSendwait(xs_messagequeue_t     mq,
                         const void *buffer,
                         xs_size_t   size,
                         xs_int32  timeout)

发送消息时,消息队列对象先从空闲消息链表上取下一个空闲消息块,把线程或者中断服务程序发送的消息内容复制到消息块上,然后把该消息块挂到消息队列的尾部,成功则返回XS_EOK。如果消息长度大于最大长度,则返回XS_ERROR。如果消息队列满了,则根据超时时间设定进行等待,超时则返回-XS_EFULL

参数 描述
mq 消息队列对象指针
buffer 消息内容
size 消息大小
timeout 超时时间

xs_err_t xs_MessageQueueSend(xs_messagequeue_t mq, const void *buffer, xs_size_t size)

该函数是timeout为0的xs_MessageQueueSendwait

参数 描述
mq 消息队列对象指针
buffer 消息内容
size 消息大小

xs_err_t xs_MessageQueueUrgentSend(xs_messagequeue_t mq, const void *buffer, xs_size_t size)

发送紧急消息和发送普通消息的区别是:当发送紧急消息时,从空闲消息链表上取下来的消息块不是挂到消息队列的队尾,而是挂到队首,这样,接收者就能够优先接收到紧急消息,从而及时进行消息处理。

参数 描述
mq 消息队列对象指针
buffer 消息内容
size 消息大小

xs_err_t xs_MessageQueueReceive(xs_messagequeue_t    mq,
                    void      *buffer,
                    xs_size_t  size,
                    xs_int32 timeout)

当队列中有消息时,接收消息。队列中没有消息时,根据超时时间设定进行等待。接收一个消息后消息队列上的队首消息被转移到了空闲消息链表的尾部。成功收到消息返回XS_EOK,超时返回XS_ETIMEOUT。接收消息失败返回-XS_ERROR

参数 描述
mq 消息队列对象指针
buffer 消息内容
size 消息大小
timeout 超时时间

xs_err_t xs_CmdControlMessageQueue(xs_messagequeue_t mq, int cmd, void *arg)

该函数用于获取或设置消息队列的其他属性。目前当cmd == XS_LINKLIST_CMD_RESET时重新初始化消息队列。

参数 描述
mq 消息队列对象指针
cmd 需要执行的命令
arg 命令的参数

信号

信号的工作机制

信号是在软件层次对中断机制的一种模拟。XiUOS中提供了信号用作异步通信的方式。

收到信号的线程对各种信号有不同的处理方法,处理方法可以分为三类:

第一种是类似中断的处理程序,对于需要处理的信号,线程可以指定处理函数,由该函数来处理。

第二种方法是,忽略某个信号,对该信号不做任何处理。

第三种方法是,对该信号的处理保留系统的默认值。

具体来说假设其他线程要向线程1通信则在线程1中安装一个信号并解除阻塞在安装的同时规定对该信号的异常处理方式。其他线程给线程1发送信号触发线程1对该信号的处理。

函数接口

xs_sighandler_t xs_InstallSignal(int signo, xs_sighandler_t handler)

该函数用于给当前线程安装一个新的信号。

参数 描述
signo 信号值
handler 设置对信号值的处理方式,可以是用户自定义的函数,SIG_IGNSIG_DFL

handler的值为SIG_IGN时,忽略该信号;
handler的值为SIG_DFL时,执行信号默认处理函数_SignalDefaultHandler
handler为函数句柄时执行用户函数。

void xs_MaskSignal(int signo)

该函数用于屏蔽一个信号。

参数 描述
signo 信号值

void xs_UnmaskSignal(int signo)

该函数用于解除对一个信号的屏蔽。

参数 描述
signo 信号值

int xs_WaitSignal(const xs_sigset_t *set, xs_siginfo_t *si, xs_int32 timeout)

等待set信号到来。如果没等到这个信号,则将该线程挂起直到等到信号或超过超时时间。如果等到信号,则将set信号指针存入si

参数 描述
set 指定等待的信号
set 指向存储等到信号信息的指针
set 超时时间

int xs_KThreadKill(TaskDescriptorPointer tid, int sig)

该函数用于给线程tid发送信号sig

参数 描述
tid 线程
sig 信号值
int xs_SysInitSignal(void)

该函数用于在内存池中给信号分配一片内存区。