计数信号量有两种典型的用法:
1.事件计数:
每次事件发生时,中断ISR会释放(Give)信号量,信号量的计数值加1 。事件处理任务每次处理一个事件会获取(Take)一次信号量,计数值减1. 信号量的值就是已发生事件数目与已处理事件数目之间的差值。用于事件的计数的计数信号量,在被创建时其计数值被初始化为0。
2.资源管理:
信号量的计数值表示可用资源的数目,一个任务获取资源的控制权,必须先获取(Take)信号量,使信号的计数值减1。当资源总数为0,表示没有资源可用。当任务利用资源完成工作后,归还信号量,信号量的计数值加1.用于资源管理的信号量,在被创建时其计数值为可用的最大资源数。
典型的生产者与消费者问题如下图示:
这里对生产者与消费者问题,进行验证:
资源:生产线上有5个箱子(共享资源),一开始都是空的。
生产者:先判断在5个箱子(共享资源)中有木有空箱子,若有空箱子则向空箱子放入数字(依次放入1,2,…10);若无空箱子则需要等待。
消费者:先判断在5个箱子(共享资源)中有木有已放入数字的箱子,若有则取出箱子的数字,进行累加处理,若无则需要等待。
1 #define BOX_NUM 5 2 uint32_t box[BOX_NUM]; 3 uint32_t put = 0,get = 0; 4 5 6 void MX_FREERTOS_Init(void) { 7 /* USER CODE BEGIN Init */ 8 9 /* USER CODE END Init */ 10 11 12 /* Create the semaphores(s) */ 13 /* definition and creation of lockSem */ 14 osSemaphoreDef(lockSem); 15 //lockSem用于对共享资源的互斥访问 16 lockSemHandle = osSemaphoreCreate(osSemaphore(lockSem), 1); 17 18 /* definition and creation of emptySem */ 19 osSemaphoreDef(emptySem); 20 //emptySem代表空箱子的资源数,初始计数值5 21 emptySemHandle = osSemaphoreCreate(osSemaphore(emptySem), 5); 22 23 /* definition and creation of fullsem */ 24 //fullSem代表装有数字箱子的资源数,初始计数值0 25 fullsemHandle = xSemaphoreCreateCounting(5, 0); 26 27 /* USER CODE BEGIN RTOS_TIMERS */ 28 /* start timers, add new ones, ... */ 29 /* USER CODE END RTOS_TIMERS */ 30 31 /* Create the thread(s) */ 32 /* definition and creation of vTask1 */ 33 osThreadDef(vTask1, producer_task, osPriorityNormal, 0, 256); 34 vTask1Handle = osThreadCreate(osThread(vTask1), NULL); 35 36 /* definition and creation of vTaks2 */ 37 osThreadDef(vTaks2, consumer_task, osPriorityHigh, 0, 256); 38 vTaks2Handle = osThreadCreate(osThread(vTaks2), NULL); 39 40 /* USER CODE BEGIN RTOS_THREADS */ 41 /* add threads, ... */ 42 /* USER CODE END RTOS_THREADS */ 43 44 /* USER CODE BEGIN RTOS_QUEUES */ 45 /* add queues, ... */ 46 /* USER CODE END RTOS_QUEUES */ 47 } 48 49 /* producer_task function */ 50 void producer_task(void const * argument) 51 { 52 53 /* USER CODE BEGIN producer_task */ 54 static int Count = 0; 55 /* Infinite loop */ 56 while(Count < 10) 57 { 58 //尝试获取一个空箱子 59 osSemaphoreWait(emptySemHandle,osWaitForever); 60 61 //互斥访问共享资源 62 osSemaphoreWait(lockSemHandle,osWaitForever); 63 64 //向空箱子放入数字 65 box[put % BOX_NUM] = Count + 1; 66 67 printf("the producer package box[%d] which content is : %d ",put % BOX_NUM,box[put % BOX_NUM]); 68 69 //放入数字次数 70 put++; 71 72 //当对共享资源访问完毕,解锁。 73 osSemaphoreRelease(lockSemHandle); 74 75 //释放一个“满”信号量,代表已完成对一个box的加工 76 osSemaphoreRelease(fullsemHandle); 77 78 //循环执行次数 79 Count++; 80 81 //生产者休息一会 82 osDelay(20); 83 } 84 85 printf("producer finish!!!!! "); 86 87 osThreadSuspend(vTask1Handle); 88 /* USER CODE END producer_task */ 89 } 90 91 /* consumer_task function */ 92 void consumer_task(void const * argument) 93 { 94 /* USER CODE BEGIN consumer_task */ 95 static int sum = 0; 96 /* Infinite loop */ 97 while(1) 98 { 99 //尝试获取一个已放入数字箱子 100 osSemaphoreWait(fullsemHandle,osWaitForever); 101 102 //互斥访问共享资源 103 osSemaphoreWait(lockSemHandle,osWaitForever); 104 105 //获取箱子里数字进行累加计算 106 sum = sum + box[get % BOX_NUM]; 107 108 printf("the consumer : box[%d] get a num %d ",get%BOX_NUM, box[get%BOX_NUM]); 109 110 //获取数字的次数 111 get++; 112 113 //当对共享资源访问完毕,解锁。 114 osSemaphoreRelease(lockSemHandle); 115 116 //释放一个空箱子资源 117 osSemaphoreRelease(emptySemHandle); 118 119 //获取10次数字后退出 120 if(get == 10) 121 { 122 break; 123 } 124 125 osDelay(120); 126 } 127 128 printf("the consumer sum is: %d ", sum); 129 printf("the consumer exit! "); 130 131 osThreadSuspend(vTaks2Handle); 132 /* USER CODE END consumer_task */ 133 }
测试验证结果: