RTX线程通信之——信号量

Posted 玖道

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RTX线程通信之——信号量相关的知识,希望对你有一定的参考价值。

本文目录

Semaphores

信号量是操作系统中极为重要的概念,它实现了线程之间的同步资源访问。

概述

Semaphores are used to manage and protect access to shared resources. Semaphores are very similar to Mutexes. Whereas a Mutex permits just one thread to access a shared resource at a time, a semaphore can be used to permit a fixed number of threads/ISRs to access a pool of shared resources. Using semaphores, access to a group of identical peripherals can be managed (for example multiple DMA channels).

直接抓重点,信号量的特点如下:

  • 信号量是实现线程通信的机制之一,类似互斥锁
  • 信号量用于管理和保护共享资源。
  • 信号量是一种容器,可以容纳很多tokens,即多种资源。

A semaphore object should be initialized to the maximum number of available tokens. This number of available resources is specified as parameter of the osSemaphoreNew function. Each time a semaphore token is obtained with osSemaphoreAcquire (in available state), the semaphore count is decremented. When the semaphore count is 0 (i.e. depleted state), no more semaphore tokens can be obtained. The thread/ISR that tries to obtain the semaphore token needs to wait until the next token is free. Semaphores are released with osSemaphoreRelease incrementing the semaphore count.

  • 信号量在创建之时需要指定其能容纳的最大tokens数。
  • 线程获取某信号量时,如果该信号量中至少有一个tokens,则线程获取成功,信号量计数减一;否则该线程进入等待状态,直到该信号量拥有tokens。同时,线程在执行过程中,也可能向信号量中添加tokens,信号量加一。

RTX信号量API

类型

  • osSemaphoreAttr_t : 信号量属性结构体
  • osSemaphoreId_t : 信号量ID

函数

osSemaphoreNew

osSemaphoreId_t osSemaphoreNew(uint32_t max_count,uint32_t initial_count,const osSemaphoreAttr_t* attr)
// 输入
* max_count : 最大tokens个数
* initial_count: 初始化tokens个数
* attr: 信号量属性结构体
// 输出
* 信号量ID

osSemaphoreGetName

const char* osSemaphoreGetName(osSemaphoreId_t semaphore_id)
// 输入
* semaphore_id : 信号量ID
// 输出
* 信号量的名字

osSemaphoreAcquire

osStatus_t osSemaphoreAcquire(osSemaphoreId_t semephore_id,uint32_t timeout)
// 输入
* semaphore_id : 信号量ID
* timeout : 超时设定
// 输出
* 函数执行状态码:osOK,osErrorTimeout,osErrorResource,osErrorParameter

osSemaphoreRelease

osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id)
// 输入
* 信号量ID
// 输出
* 函数执行状态:osOK,osErrorResource,osErrorParameter

osSemaphoreGetCount

uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id)
// 输入
* 信号量ID
// 输出
* 可获取的tokens个数

osSemaphoreDelete

osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id)
// 输入
* 信号量ID
// 输出
* 函数执行状态:osOK,osErrorParameter,osErrorResource,osErrorISR

原理

如何通过信号量来实现线程之间的资源同步访问?

A multiplex limits the number of threads that can access a critical section of code. For example, this could be a function accessing DMA resources which can only support a limited number of calls.

To allow multiple threads to run the function, initialize a semaphore to the maximum number of threads that can be allowed. The number of tokens in the semaphore represents the number of additional threads that may enter. If this number is zero, then the next thread trying to access the function will have to wait until one of the other threads exits and releases its token. When all threads have exited the token number is back to n. The following example shows the code for one of the threads that might access the resource:

其实信号量的本质很简单,比如一辆车就是一个信号量,该车只有18个座位,有空位,则乘客(线程)可以坐下(获取成功),否则,乘客只能站着(线程阻塞,等待),直到有人离开座位(释放信号量),才能有机会坐下(获取到信号量)。具体谁获得这个座位,得看谁速度最快(底层靠调度算法)。

osSemaphoreId_t multiplex_id;
 
void thread_n (void) 
  multiplex_id = osSemaphoreNew(3U, 3U, NULL);   // 最多三个 tokens,初始化为3个tokens
  while(1) 
    osSemaphoreAcquire(multiplex_id, osWaitForever);  // 获取信号量成功,否则无限等待
    // do something
    osSemaphoreRelease(multiplex_id);  // 释放信号量
  

生产者-消费者模型

The producer-consumer problem can be solved using two semaphores.

A first semaphore (empty_id) counts down the available (empty) buffers.

A second semaphore (filled_id) counts up the used (filled) buffers. It is crucial for the correct behaviour that the threads acquire and release on both semaphores in the given sequence.

生产者-消费者模型是线程同步的经典案例,该问题可以通过创建两个信号量来结局。不了解生产者-消费者模型的读者可自行百度,或参考《现代操作系统》

#define BUFFER_SIZE 10U
// 创建量信号量
osSemaphoreId_t empty_id = osSemaphoreNew(BUFFER_SIZE, BUFFER_SIZE, NULL);  
osSemaphoreId_t filled_id = osSemaphoreNew(BUFFER_SIZE, 0U, NULL);          
 
void producer_thread (void) 
  while(1) 
    osSemaphoreAcquire(empty_id, osWaitForever); 
    // produce data
    osSemaphoreRelease(filled_id);
  

void consumer_thread (void) 
  while(1)
    osSemaphoreAcquire(filled_id, osWaitForever); 
    // consume data
    osSemaphoreRelease(empty_id);
  

使用步骤

1.首先,创建信号量属性结构体

static const osSemaphoreAttr_t semaphore1 = 
    .name = "semaphore_1",
;

2.创建句柄,即信号量ID

osSemaphoreId_t sem1;

3.创建信号量,并设定一个初始tokens数。

sem1 = osSemaphoreNew(maxTokenCount,initialTokenCount,&semaphore1);

It is important to understand that semaphore tokens may also be created and destroyed as threads run.

官方案例

#include "cmsis_os2.h"                          // CMSIS RTOS header file
 
osSemaphoreId_t sid_Semaphore;                  // semaphore id
osThreadId_t tid_Thread_Semaphore;              // thread id
 
void Thread_Semaphore (void *argument);         // thread function
int Init_Semaphore (void) 
  sid_Semaphore = osSemaphoreNew(2U, 2U, NULL);
  if (sid_Semaphore == NULL) 
    ; // Semaphore object not created, handle failure
   
  tid_Thread_Semaphore = osThreadNew(Thread_Semaphore, NULL, NULL);
  if (tid_Thread_Semaphore == NULL) 
    return(-1);
  
  return(0);

 
void Thread_Semaphore (void *argument)    // semaphore function
  osStatus_t val;
  while (1) 
    ; // Insert thread code here...
    val = osSemaphoreAcquire(sid_Semaphore, 10U);       // wait for max. 10 ticks for semaphore token to get available
    switch (val) 
      case osOK:
        ; // Use protected code here...
        osSemaphoreRelease(sid_Semaphore);              // return a token back to a semaphore
        break;
      case osErrorResource:
        break;
      case osErrorParameter:
        break;
      default:
        break;
    
    osThreadYield();                                    // suspend thread
  

小结

本文主要介绍了信号量这一操作系统对象,重点如下:

  • 信号量的概念
  • 信号量的原理
  • 生产者-消费者模型
  • 信号量的函数接口和使用步骤

当然,本文内容只是讲了信号量的冰山一角,对信号量有了一个初步感性认识。信号量是操作系统中一个非常重要的概念,有很多细节需要注意,也需要查看很多资料,然后在实际运用中进行理解~

任何疑问,欢迎留言~

参考资料

☞官方资料:信号量

以上是关于RTX线程通信之——信号量的主要内容,如果未能解决你的问题,请参考以下文章

RTX线程通信之——信号量

RTX线程通信之——线程标志

RTX线程通信之——线程标志

RTX线程通信之——线程标志

RTX线程通信之——线程标志

RTX线程通信之——消息队列