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);
}

參考:嵌入式實時操作系統的多線程計算

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章