μC/OS-II---消息队列管理2(os_q.c)

目录

  • 消息队列的主要优点
  • 消息队列和消息邮箱
  • 消息队列相关操作
    • 向消息队列发送消息(FIFO)
    • 向消息队列发送消息(LIFO)
    • 向消息队列发送消息(扩展)
    • 消息队列获取/无等待
    • 清空消息队列
    • 消息队列信息获取
    • 消息队列中断等待

在这里插入图片描述

消息队列的主要优点

  • 消息队列的主要优点是解耦和异步通信。发送者和接收者之间不需要直接建立连接,它们只需要知道消息队列的名称或标识符即可。发送者将消息发送到队列中后,可以继续执行其他任务,而不需要等待接收者处理消息。接收者可以在合适的时候从队列中获取消息进行处理,这样可以实现异步通信,提高系统的并发性和响应性。
  • 通常会在消息队列中引入消息标识符或者消息类型。发送者在发送消息时,会附带一个标识符或类型,接收者在接收消息时,会根据标识符或类型来判断是否是自己需要处理的消息。这样可以确保每个进程只处理属于自己的消息,避免了拿错信息的问题。
  • 此外,还可以使用互斥锁或其他同步机制来保证在读取和写入消息队列时的原子性操作,避免多个进程同时对消息队列进行读写操作而导致的竞争条件。

消息队列和消息邮箱

  • 消息队列是一个独立的数据结构,多个进程可以共享同一个消息队列,而消息邮箱是与进程关联的,每个进程都有自己的邮箱。此外,消息队列通常是先进先出(FIFO)的,而消息邮箱可以根据实现方式不同具有不同的特性,比如可以是先进先出或者按优先级处理消息。
  • Task也可以设计有“私有”消息队列模式。
  • 总的来说,消息队列更适合实现多个进程之间的解耦和异步通信,而消息邮箱更适合实现单个进程内的消息传递。

消息队列相关操作

向消息队列发送消息(FIFO)

#if OS_Q_POST_EN > 0u
INT8U  OSQPost (OS_EVENT  *pevent,
								void      *pmsg)
{
	OS_Q      *pq;
#if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                       /* Validate 'pevent'                            */
	{
		return (OS_ERR_PEVENT_NULL);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_Q)        /* Validate event block type                    */
	{
		return (OS_ERR_EVENT_TYPE);
	}
	
	OS_ENTER_CRITICAL();
	
	if (pevent->OSEventGrp != 0u)                      /* See if any task pending on queue             */
	{
		/* Ready highest priority task waiting on event */
		(void)OS_EventTaskRdy (pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
		OS_EXIT_CRITICAL();
		OS_Sched();                                    /* Find highest priority task ready to run      */
		return (OS_ERR_NONE);
	}
	
	pq = (OS_Q *)pevent->OSEventPtr;                   /* Point to queue control block                 */
	
	if (pq->OSQEntries >= pq->OSQSize)                 /* Make sure queue is not full                  */
	{
		OS_EXIT_CRITICAL();
		return (OS_ERR_Q_FULL);
	}
	
	*pq->OSQIn++ = pmsg;                               /* Insert message into queue                    */
	pq->OSQEntries++;                                  /* Update the nbr of entries in the queue       */
	
	if (pq->OSQIn == pq->OSQEnd)                       /* Wrap IN ptr if we are at end of queue        */
	{
		pq->OSQIn = pq->OSQStart;
	}
	
	OS_EXIT_CRITICAL();
	return (OS_ERR_NONE);
}
#endif

向消息队列发送消息(LIFO)

#if OS_Q_POST_FRONT_EN > 0u
INT8U  OSQPostFront (OS_EVENT  *pevent,
										 void      *pmsg)
{
	OS_Q      *pq;
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                      /* Validate 'pevent'                             */
	{
		return (OS_ERR_PEVENT_NULL);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_Q)       /* Validate event block type                     */
	{
		return (OS_ERR_EVENT_TYPE);
	}
	
	OS_ENTER_CRITICAL();
	
	if (pevent->OSEventGrp != 0u)                     /* See if any task pending on queue              */
	{
		/* Ready highest priority task waiting on event  */
		(void)OS_EventTaskRdy (pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
		OS_EXIT_CRITICAL();
		OS_Sched();                                   /* Find highest priority task ready to run       */
		return (OS_ERR_NONE);
	}
	
	pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
	
	if (pq->OSQEntries >= pq->OSQSize)                /* Make sure queue is not full                   */
	{
		OS_EXIT_CRITICAL();
		return (OS_ERR_Q_FULL);
	}
	
	if (pq->OSQOut == pq->OSQStart)                   /* Wrap OUT ptr if we are at the 1st queue entry */
	{
		pq->OSQOut = pq->OSQEnd;
	}
	
	pq->OSQOut--;
	*pq->OSQOut = pmsg;                               /* Insert message into queue                     */
	pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
	OS_EXIT_CRITICAL();
	return (OS_ERR_NONE);
}
#endif

向消息队列发送消息(扩展)

#if OS_Q_POST_OPT_EN > 0u
INT8U  OSQPostOpt (OS_EVENT  *pevent,
									 void      *pmsg,
									 INT8U      opt)
{
	OS_Q      *pq;
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                      /* Validate 'pevent'                             */
	{
		return (OS_ERR_PEVENT_NULL);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_Q)       /* Validate event block type                     */
	{
		return (OS_ERR_EVENT_TYPE);
	}
	
	OS_ENTER_CRITICAL();
	
	if (pevent->OSEventGrp != 0x00u)                  /* See if any task pending on queue              */
	{
		if ((opt & OS_POST_OPT_BROADCAST) != 0x00u)   /* Do we need to post msg to ALL waiting tasks ? */
		{
			while (pevent->OSEventGrp != 0u)          /* Yes, Post to ALL tasks waiting on queue       */
			{
				(void)OS_EventTaskRdy (pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
			}
		}
		
		else                                          /* No,  Post to HPT waiting on queue             */
		{
			(void)OS_EventTaskRdy (pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
		}
		
		OS_EXIT_CRITICAL();
		
		if ((opt & OS_POST_OPT_NO_SCHED) == 0u)       /* See if scheduler needs to be invoked          */
		{
			OS_Sched();                               /* Find highest priority task ready to run       */
		}
		
		return (OS_ERR_NONE);
	}
	
	pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
	
	if (pq->OSQEntries >= pq->OSQSize)                /* Make sure queue is not full                   */
	{
		OS_EXIT_CRITICAL();
		return (OS_ERR_Q_FULL);
	}
	
	if ((opt & OS_POST_OPT_FRONT) != 0x00u)           /* Do we post to the FRONT of the queue?         */
	{
		if (pq->OSQOut == pq->OSQStart)               /* Yes, Post as LIFO, Wrap OUT pointer if we ... */
		{
			pq->OSQOut = pq->OSQEnd;                  /*      ... are at the 1st queue entry           */
		}
		
		pq->OSQOut--;
		*pq->OSQOut = pmsg;                           /*      Insert message into queue                */
	}
	
	else                                              /* No,  Post as FIFO                             */
	{
		*pq->OSQIn++ = pmsg;                          /*      Insert message into queue                */
		
		if (pq->OSQIn == pq->OSQEnd)                  /*      Wrap IN ptr if we are at end of queue    */
		{
			pq->OSQIn = pq->OSQStart;
		}
	}
	
	pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
	OS_EXIT_CRITICAL();
	return (OS_ERR_NONE);
}
#endif

消息队列获取/无等待

#if OS_Q_ACCEPT_EN > 0u
void  *OSQAccept (OS_EVENT  *pevent,
									INT8U     *perr)
{
	void      *pmsg;
	OS_Q      *pq;
#if OS_CRITICAL_METHOD == 3u                     /* Allocate storage for CPU status register           */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
	
	if (perr == (INT8U *)0)
	{
		OS_SAFETY_CRITICAL_EXCEPTION();
		return ((void *)0);
	}
	
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                 /* Validate 'pevent'                                  */
	{
		*perr = OS_ERR_PEVENT_NULL;
		return ((void *)0);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_Q)  /* Validate event block type                          */
	{
		*perr = OS_ERR_EVENT_TYPE;
		return ((void *)0);
	}
	
	OS_ENTER_CRITICAL();
	pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
	
	if (pq->OSQEntries > 0u)                     /* See if any messages in the queue                   */
	{
		pmsg = *pq->OSQOut++;                    /* Yes, extract oldest message from the queue         */
		pq->OSQEntries--;                        /* Update the number of entries in the queue          */
		
		if (pq->OSQOut == pq->OSQEnd)            /* Wrap OUT pointer if we are at the end of the queue */
		{
			pq->OSQOut = pq->OSQStart;
		}
		
		*perr = OS_ERR_NONE;
	}
	
	else
	{
		*perr = OS_ERR_Q_EMPTY;
		pmsg  = (void *)0;                       /* Queue is empty                                     */
	}
	
	OS_EXIT_CRITICAL();
	return (pmsg);                               /* Return message received (or NULL)                  */
}
#endif

清空消息队列

#if OS_Q_FLUSH_EN > 0u
INT8U  OSQFlush (OS_EVENT *pevent)
{
	OS_Q      *pq;
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                      /* Validate 'pevent'                             */
	{
		return (OS_ERR_PEVENT_NULL);
	}
	
	if (pevent->OSEventType != OS_EVENT_TYPE_Q)       /* Validate event block type                     */
	{
		return (OS_ERR_EVENT_TYPE);
	}
	
#endif
	OS_ENTER_CRITICAL();
	pq             = (OS_Q *)pevent->OSEventPtr;      /* Point to queue storage structure              */
	pq->OSQIn      = pq->OSQStart;
	pq->OSQOut     = pq->OSQStart;
	pq->OSQEntries = 0u;
	OS_EXIT_CRITICAL();
	return (OS_ERR_NONE);
}
#endif

消息队列信息获取

#if OS_Q_QUERY_EN > 0u
INT8U  OSQQuery (OS_EVENT  *pevent,
								 OS_Q_DATA *p_q_data)
{
	OS_Q       *pq;
	INT8U       i;
	OS_PRIO    *psrc;
	OS_PRIO    *pdest;
#if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */
	OS_CPU_SR   cpu_sr = 0u;
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                       /* Validate 'pevent'                            */
	{
		return (OS_ERR_PEVENT_NULL);
	}
	
	if (p_q_data == (OS_Q_DATA *)0)                    /* Validate 'p_q_data'                          */
	{
		return (OS_ERR_PDATA_NULL);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_Q)        /* Validate event block type                    */
	{
		return (OS_ERR_EVENT_TYPE);
	}
	
	OS_ENTER_CRITICAL();
	p_q_data->OSEventGrp = pevent->OSEventGrp;         /* Copy message queue wait list                 */
	psrc                 = &pevent->OSEventTbl[0];
	pdest                = &p_q_data->OSEventTbl[0];
	
	for (i = 0u; i < OS_EVENT_TBL_SIZE; i++)
	{
		*pdest++ = *psrc++;
	}
	
	pq = (OS_Q *)pevent->OSEventPtr;
	
	if (pq->OSQEntries > 0u)
	{
		p_q_data->OSMsg = *pq->OSQOut;                 /* Get next message to return if available      */
	}
	
	else
	{
		p_q_data->OSMsg = (void *)0;
	}
	
	p_q_data->OSNMsgs = pq->OSQEntries;
	p_q_data->OSQSize = pq->OSQSize;
	OS_EXIT_CRITICAL();
	return (OS_ERR_NONE);
}
#endif

消息队列中断等待

#if OS_Q_PEND_ABORT_EN > 0u
INT8U  OSQPendAbort (OS_EVENT  *pevent,
										 INT8U      opt,
										 INT8U     *perr)
{
	INT8U      nbr_tasks;
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
	
	if (perr == (INT8U *)0)
	{
		OS_SAFETY_CRITICAL_EXCEPTION();
		return (0u);
	}
	
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                           /* Validate 'pevent'                        */
	{
		*perr = OS_ERR_PEVENT_NULL;
		return (0u);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_Q)            /* Validate event block type                */
	{
		*perr = OS_ERR_EVENT_TYPE;
		return (0u);
	}
	
	OS_ENTER_CRITICAL();
	
	if (pevent->OSEventGrp != 0u)                          /* See if any task waiting on queue?        */
	{
		nbr_tasks = 0u;
		
		switch (opt)
		{
			case OS_PEND_OPT_BROADCAST:                    /* Do we need to abort ALL waiting tasks?   */
				while (pevent->OSEventGrp != 0u)          /* Yes, ready ALL tasks waiting on queue    */
				{
					(void)OS_EventTaskRdy (pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT);
					nbr_tasks++;
				}
				
				break;
				
			case OS_PEND_OPT_NONE:
			default:                                       /* No,  ready HPT       waiting on queue    */
				(void)OS_EventTaskRdy (pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT);
				nbr_tasks++;
				break;
		}
		
		OS_EXIT_CRITICAL();
		OS_Sched();                                        /* Find HPT ready to run                    */
		*perr = OS_ERR_PEND_ABORT;
		return (nbr_tasks);
	}
	
	OS_EXIT_CRITICAL();
	*perr = OS_ERR_NONE;
	return (0u);                                           /* No tasks waiting on queue                */
}
#endif

你可能感兴趣的:(μC/OS-II学习,c语言,操作系统)