Threadx 消息队列 queue


Threadx提供了消息队列进行线程间通信。
消息队列中消息通常按照先进先出规则传递,同时提供了把消息直接存储到队列头部的API。每个线程可以创建多个消息队列,并且可以使用多个消息队列和多个线程通信。
消息队列不支持拥有者属性,也就是任何线程可以向消息队列发送或接收消息。应用开发者保证消息队列使用的合理性。

消息传递规则

1,任何线程可以向一个消息队列发送或接收消息,消息队列不支持拥有者属性。
2,消息队列支持先进先出规则,函数_tx_queue_send发送消息都队列尾部。
3,消息队列也支持发送消息到消息头部功能,函数_tx_queue_front_send发送消息到消息头部。
4,如果消息队列有挂起的接收线程,发送消息时,可以直接把消息放到接收线程的缓冲中,这可以降低消息传递延时。
TX_THREAD线程控制块中tx_additional_suspend_info域用于存储接收线程缓冲区地址。
5,如果消息队列为空,接收线程调用_tx_queue_receive(wait_option不为0)读取消息时,线程会被挂起到队列tx_queue_suspension_list。其它线程发送消息后会恢复挂起的线程
6,如果消息队列已满,发送线程调用_tx_queue_send(wait_option不为0)发送消息时,线程会被挂起到队列tx_queue_suspension_list。其它线程接收消息时,会恢复挂起的线程。

在这里插入图片描述

消息大小

消息队列中消息大小支持是1个,2个,4个,8个和16个32位字,一个消息队列消息大小只能是其中一种,在创建消息队列时指定。
一般消息内容比较多时,使用指针来传递。创建一个消息大小为一个字的队列,存储传递的指针,线程发送或接受消息指针,而不是整个消息。
消息队列中存储消息个数有消息大小和分配的存储空间大小决定。消息个数=存储空间字节数/单个消息字节数。
存储空间由应用开发人员分配好,是在消息创建时把存储空间地址作为入参。这块存储空间可以指定在高速ram中,提供系统性能。

消息队列控制块

消息队列控制块(QCB)是用来保持运行时消息队列状态的数据结构。

typedef struct TX_QUEUE_STRUCT
{

    /* Define the queue ID used for error checking.  */
    ULONG       tx_queue_id;

    /* Define the queue's name.  */
    CHAR_PTR    tx_queue_name;

    /* Define the message size that was specified in queue creation.  */
    UINT        tx_queue_message_size;

    /* Define the total number of messages in the queue.  */
    ULONG       tx_queue_capacity;

    /* Define the current number of messages enqueue and the available
       queue storage space.  */
    ULONG       tx_queue_enqueued;
    ULONG       tx_queue_available_storage;

    /* Define pointers that represent the start and end for the queue's
       message area.  */
    ULONG_PTR   tx_queue_start;
    ULONG_PTR   tx_queue_end;

    /* Define the queue read and write pointers.  Send requests use the write
       pointer while receive requests use the read pointer.  */
    ULONG_PTR   tx_queue_read;
    ULONG_PTR   tx_queue_write;

    /* Define the queue suspension list head along with a count of
       how many threads are suspended.  */
    struct TX_THREAD_STRUCT  *tx_queue_suspension_list;
    ULONG                    tx_queue_suspended_count;

    /* Define the created list next and previous pointers.  */
    struct TX_QUEUE_STRUCT
        *tx_queue_created_next,
        *tx_queue_created_previous;

} TX_QUEUE;
意义
tx_queue_id 队列id标志
tx_queue_name 队列名字,创建者指定
tx_queue_message_size 消息大小
tx_queue_capacity 队列容量(消息个数最大值)
tx_queue_enqueued
tx_queue_available_storage 队列中可用存储空间
tx_queue_start 指向消息队列头部指针
tx_queue_end 指向消息队列尾部指针
tx_queue_read 读指针,指向消息队列中第一个可读消息地址
tx_queue_write 写指针,指向消息队列中第一个可写消息地址
tx_queue_suspension_list 挂起队列指针,挂起读线程或发送线程
tx_queue_suspended_count 挂起队列中线程个数
tx_queue_created_next 指向下一个消息队列指针
tx_queue_created_previous 指向前一个消息队列指针

消息队列list

系统中所有信号量控制块挂载一个双向链表_tx_queue_created_ptr中,tx_queue_created_next指向下一个消息队列指针,tx_queue_created_previous指向前一个消息队列指针。

在这里插入图片描述

消息队列API

函数 描述
_tx_queue_create 创建消息队列
_tx_queue_delete 删除消息队列
_tx_queue_flush 清空消息队列中消息或挂起队列中线程
_tx_queue_info_get 获取消息队列信息
_tx_queue_receive 读取消息队列消息
_tx_queue_send 发送消息到队列尾部
_tx_queue_front_send 发送消息到队列头部
_tx_queue_prioritize 调整挂起队列头部为最高优先级线程

创建消息队列_tx_queue_create

message_size当个消息占用几个 32位字
queue_start消息队列存储空间首地址
queue_size存储空间大小

UINT    _tx_queue_create(TX_QUEUE *queue_ptr, CHAR *name_ptr, UINT message_size,
                         VOID *queue_start, ULONG queue_size)
{

    TX_INTERRUPT_SAVE_AREA

    TX_QUEUE    *tail_ptr;                      /* Working queue pointer     */
    REG_1 UINT  capacity;                       /* Queue's message capacity  */
    REG_2 UINT  used_words;                     /* Number of words used      */


    /* Setup the basic queue fields.  */
    queue_ptr -> tx_queue_name =             name_ptr;
    queue_ptr -> tx_queue_suspension_list =  TX_NULL;
    queue_ptr -> tx_queue_suspended_count =  0;

    /* Save the message size in the control block.  */
    queue_ptr -> tx_queue_message_size =  message_size;

    /* Determine how many messages will fit in the queue area and the number
       of ULONGs used.  */
    #def 计算消息队列容量,message_size表示占用几个sizeof(ULONG),queue_size 表示总空间大小(字节),容量为总的空间字节/单个消息字节,capacity存储了计算后消息队列能够存储消息个数,used_words 为消息队列容量,单位是字节
    if (message_size == TX_1_ULONG)
    {
        capacity =  queue_size / (TX_1_ULONG * sizeof(ULONG));
        used_words =  capacity;
    }
    else if (message_size == TX_2_ULONG)
    {
        capacity =  queue_size / (TX_2_ULONG * sizeof(ULONG));
        used_words =  capacity * TX_2_ULONG;
    }
    else if (message_size == TX_4_ULONG)
    {
        capacity =  queue_size / (TX_4_ULONG * sizeof(ULONG));
        used_words =  capacity * TX_4_ULONG;
    }
    else if (message_size == TX_8_ULONG)
    {
        capacity =  queue_size / (TX_8_ULONG * sizeof(ULONG));
        used_words =  capacity * TX_8_ULONG;
    }
    else
    {
        capacity =  queue_size / (TX_16_ULONG * sizeof(ULONG));
        used_words =  capacity * TX_16_ULONG;
    }

    /* Save the starting address and calculate the ending address of
       the queue.  Note that the ending address is really one past the
       end!  */
       #def 设置消息队列存储空间起始地址和终止地址
    queue_ptr -> tx_queue_start = (ULONG_PTR) queue_start;
    queue_ptr -> tx_queue_end = ((ULONG_PTR) queue_start) + used_words;

    /* Set the read and write pointers to the beginning of the queue
       area.  */
      #def 初始消息队列读写指针为存储空间起始地址
    queue_ptr -> tx_queue_read = (ULONG_PTR) queue_start;
    queue_ptr -> tx_queue_write = (ULONG_PTR) queue_start;

    /* Setup the number of enqueued messages and the number of message
       slots available in the queue.  */
    #def 初始空间容量和当前消息个数,剩余空间(单位都是消息个数,不是字节)
    queue_ptr -> tx_queue_enqueued =           0;
    queue_ptr -> tx_queue_available_storage =  capacity;
    queue_ptr -> tx_queue_capacity =           capacity;

    /* Disable interrupts to put the queue on the created list.  */
    #def 禁止中断,也就是禁止中断处理或其他线程打断本线程。处理全局变量
    TX_DISABLE

    /* Setup the queue ID to make it valid.  */
    #def 表示消息队列有效标志
    queue_ptr -> tx_queue_id =  TX_QUEUE_ID;

    /* Place the queue on the list of created queues.  First,
       check for an empty list.  */
       #def 插入_tx_queue_created_ptr list
    if (_tx_queue_created_ptr)
    {

        /* Pickup tail pointer.  */
        tail_ptr =  _tx_queue_created_ptr -> tx_queue_created_previous;

        /* Place the new queue in the list.  */
        _tx_queue_created_ptr -> tx_queue_created_previous =  queue_ptr;
        tail_ptr -> tx_queue_created_next =  queue_ptr;

        /* Setup this queues's created links.  */
        queue_ptr -> tx_queue_created_previous =  tail_ptr;
        queue_ptr -> tx_queue_created_next =      _tx_queue_created_ptr;
    }
    else
    {

        /* The created queue list is empty.  Add queue to empty list.  */
        _tx_queue_created_ptr =                   queue_ptr;
        queue_ptr -> tx_queue_created_next =      queue_ptr;
        queue_ptr -> tx_queue_created_previous =  queue_ptr;
    }

    /* Increment the number of queues created counter.  */
    _tx_queue_created_count++;

    /* Restore interrupts.  */
    TX_RESTORE

    /* Return TX_SUCCESS.  */
    return (TX_SUCCESS);
}

删除队列_tx_queue_delete

UINT    _tx_queue_delete(TX_QUEUE *queue_ptr)
{

    TX_INTERRUPT_SAVE_AREA

    TX_THREAD       *thread_ptr;                /* Working thread pointer  */


    /* Disable interrupts to remove the queue from the created list.  */
    #def 禁止中断,防止处理被打断,处理全局变量
    TX_DISABLE

    /* Decrement the number of queues created.  */
    _tx_queue_created_count--;

    /* Clear the queue ID to make it invalid.  */
    #def 标记为无效
    queue_ptr -> tx_queue_id =  0;

    /* See if the queue is the only one on the list.  */
    #def 从_tx_queue_created_ptr 链表中删除
    if (queue_ptr == queue_ptr -> tx_queue_created_next)
    {

        /* Only created queue, just set the created list to NULL.  */
        _tx_queue_created_ptr =  TX_NULL;
    }
    else
    {

        /* Link-up the neighbors.  */
        (queue_ptr -> tx_queue_created_next) -> tx_queue_created_previous =
            queue_ptr -> tx_queue_created_previous;
        (queue_ptr -> tx_queue_created_previous) -> tx_queue_created_next =
            queue_ptr -> tx_queue_created_next;

        /* See if we have to update the created list head pointer.  */
        if (_tx_queue_created_ptr == queue_ptr)

            /* Yes, move the head pointer to the next link. */
            _tx_queue_created_ptr =  queue_ptr -> tx_queue_created_next;
    }

	#def 先禁止线程抢占,然后TX_RESTORE开中断,之后处理可以被中断打断,减少中断处理时延,但不能被高优先级抢占,因为高优先级可能使用这个队列
    /* Temporarily disable preemption.  */
    _tx_thread_preempt_disable++;

    /* Restore interrupts.  */
    TX_RESTORE

    /* Walk through the queue list to resume any and all threads suspended
       on this queue.  */
    #def 清除挂起链表中线程,恢复线程
    thread_ptr =  queue_ptr -> tx_queue_suspension_list;
    while (queue_ptr -> tx_queue_suspended_count)
    {
        /* Lockout interrupts.  */
        TX_DISABLE

        /* Clear the cleanup pointer, this prevents the timeout from doing
           anything.  */
        thread_ptr -> tx_suspend_cleanup =  TX_NULL;

        /* Temporarily disable preemption again.  */
        _tx_thread_preempt_disable++;

        /* Restore interrupts.  */
        TX_RESTORE

        /* Yes, deactivate the thread's timer just in case.  */
        _tx_timer_deactivate(&(thread_ptr -> tx_thread_timer));

        /* Clear the remaining time to ensure timer doesn't get activated.  */
        thread_ptr -> tx_thread_timer.tx_remaining_ticks =  0;

        /* Set the return status in the thread to TX_DELETED.  */
        thread_ptr -> tx_suspend_status =  TX_DELETED;

        /* Move the thread pointer ahead.  */
        thread_ptr =  thread_ptr -> tx_suspended_next;

        /* Resume the thread.  */
        _tx_thread_resume(thread_ptr -> tx_suspended_previous);

        /* Decrease the suspended count.  */
        queue_ptr -> tx_queue_suspended_count--;
    }

	#def 禁止中断,为了操作_tx_thread_preempt_disable,开启抢占
    /* Disable interrupts.  */
    TX_DISABLE

    /* Release previous preempt disable.  */
    _tx_thread_preempt_disable--;

    /* Restore interrupts.  */
    TX_RESTORE

    /* Check for preemption.  */
    #def 前面已经恢复了线程,可能有高优先级线程需要调度
    if (_tx_thread_current_ptr != _tx_thread_execute_ptr)

        /* Transfer control to system.  */
        #def 线程切换
        _tx_thread_system_return();

    /* Return TX_SUCCESS.  */
    return (TX_SUCCESS);
}

清空消息队列_tx_queue_flush

_tx_queue_flush函数清空消息队列中消息,挂起线程,设置为初始化状态。

UINT    _tx_queue_flush(TX_QUEUE *queue_ptr)
{

    TX_INTERRUPT_SAVE_AREA

    TX_THREAD       *suspension_list;           /* Pickup the suspension list head  */
    UINT            suspended_count;            /* Count of suspended threads       */
    TX_THREAD       *thread_ptr;                /* Working thread pointer           */


    /* Initialize the suspended count.  */
    suspended_count =  0;

    /* Disable interrupts to reset various queue parameters.  */
    #def 禁止中断,下面操作全局变量,防止被打断,被抢占
    TX_DISABLE

    /* Determine if there is something on the queue.  */
    #def 如果队列不为空,清除消息,恢复初始化值
    if (queue_ptr -> tx_queue_enqueued)
    {

        /* Yes, there is something in the queue.  */

        /* Reset the queue parameters to erase all of the queued messages.  */
        #def 设置为空,初始化
        queue_ptr -> tx_queue_enqueued =           0;
        queue_ptr -> tx_queue_available_storage =  queue_ptr -> tx_queue_capacity;
        queue_ptr -> tx_queue_read =               queue_ptr -> tx_queue_start;
        queue_ptr -> tx_queue_write =              queue_ptr -> tx_queue_start;

        /* Now determine if there are any threads suspended on a full queue.  */
        #def 如果有挂起的线程,删除list中线程,并恢复线程状态
        if (queue_ptr -> tx_queue_suspended_count)
        {

            /* Yes, there are threads suspended on this queue, they must be
               resumed!  */

            /* Copy the information into temporary variables.  */
            suspension_list =  queue_ptr -> tx_queue_suspension_list;
            suspended_count =  queue_ptr -> tx_queue_suspended_count;

            /* Clear the queue variables.  */
            queue_ptr -> tx_queue_suspension_list =  TX_NULL;
            queue_ptr -> tx_queue_suspended_count =  0;

            /* Temporarily disable preemption.  */
            #def 禁止抢占
            _tx_thread_preempt_disable++;
        }
    }

    /* Restore interrupts.  */
    TX_RESTORE

    /* Walk through the queue list to resume any and all threads suspended
       on this queue.  */
     #def 恢复线程
    if (suspended_count)
    {

        /* Pickup the thread to resume.  */
        thread_ptr =  suspension_list;
        do
        {

            /* Resume the next suspended thread.  */

            /* Lockout interrupts.  */
            TX_DISABLE

            /* Clear the cleanup pointer, this prevents the timeout from doing
               anything.  */
            thread_ptr -> tx_suspend_cleanup =  TX_NULL;

            /* Temporarily disable preemption again.  */
            _tx_thread_preempt_disable++;

            /* Restore interrupts.  */
            TX_RESTORE

            /* Yes, deactivate the thread's timer just in case.  */
            _tx_timer_deactivate(&(thread_ptr -> tx_thread_timer));

            /* Clear the remaining time to ensure timer doesn't get activated.  */
            thread_ptr -> tx_thread_timer.tx_remaining_ticks =  0;

            /* Set the return status in the thread to TX_SUCCESS.  */
            thread_ptr -> tx_suspend_status =  TX_SUCCESS;

            /* Move the thread pointer ahead.  */
            thread_ptr =  thread_ptr -> tx_suspended_next;

            /* Resume the thread.  */
            _tx_thread_resume(thread_ptr -> tx_suspended_previous);

            /* Continue while there are suspended threads.  */
        }
        while (--suspended_count);

        /* Disable interrupts.  */
        TX_DISABLE

        /* Restore previous preempt posture.  */
        _tx_thread_preempt_disable--;

        /* Restore interrupts.  */
        TX_RESTORE

        /* Check for preemption.  */
        #def 恢复线程或中断后,可能有高优先级线程,进行调度切换
        if (_tx_thread_current_ptr != _tx_thread_execute_ptr)

            /* Transfer control to system.  */
            _tx_thread_system_return();
    }

    /* Return TX_SUCCESS.  */
    return (TX_SUCCESS);
}

参考:嵌入式实时操作系统的多线程计算

发布了41 篇原创文章 · 获赞 2 · 访问量 3246

猜你喜欢

转载自blog.csdn.net/qq_45683435/article/details/104209414