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 | 指向前一个消息队列指针 |
系统中所有信号量控制块挂载一个双向链表_tx_queue_created_ptr中,tx_queue_created_next指向下一个消息队列指针,tx_queue_created_previous指向前一个消息队列指针。
函数 | 描述 |
---|---|
_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 | 调整挂起队列头部为最高优先级线程 |
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);
}
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函数清空消息队列中消息,挂起线程,设置为初始化状态。
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);
}
参考:嵌入式实时操作系统的多线程计算