木子剑
生命不熄,学习不止!

先看官方描述:

 

 

【提供例子为,一个任务为生产者,一个任务为消费者,一个共享仓库】

当生产者到来时,要先确认仓库是不是full信号量满了?如果满了放不下了就要等,不满就可以继续一下步;就是获取仓库的mutex互斥锁,如果之前仓库有锁,

生产者还得等等,等仓库解锁后,最后可以往仓库更新数据了。最后释放empty信号量和 mutex互斥锁,完成一个生产的操作。(因为消费者只关心empty,所以要+1)

 

当消费者到来时,要先确认仓库是不是empty,如果空了就取不到数据了要等一会,当不空了说明有数据了,就要获取仓库的mutex互斥锁,如果之前仓库有锁,

消费者也要等等,等仓库解锁后,最后可以往仓库取数据了。最后释放full信号量和 mutex互斥锁,完成一个消费的操作。(因为生产者只关心full,所以要full+1)

 

官方的源码有点乱,就改成上述原理描述的:

在TencentOS-tiny\board\SWM320_DISCOVERY\BSP\Src下新建tOS_semaphore.c,内容如下

#include "tos_k.h"
#include "mcu_init.h"

#define STK_SIZE_TASK_PRODUCER      512   // 生产者任务栈大小
#define STK_SIZE_TASK_CONSUMER      512   // 消费者

k_stack_t stack_task_producer[STK_SIZE_TASK_PRODUCER];  // 生产数据
k_stack_t stack_task_consumer[STK_SIZE_TASK_CONSUMER];  // 消费数据

k_task_t task_producer;  // 任务句柄
k_task_t task_consumer;

extern void entry_task_producer(void *arg);  // 任务回调函数
extern void entry_task_consumer(void *arg);

k_mutex_t buffer_locker;  // 互斥锁
k_sem_t full;             // 信号量FULL
k_sem_t empty;            // 信号量EMPTY

#define RESOURCE_COUNT_MAX      3   // 最大生产值

struct resource_st {
    int cursor;
    uint32_t buffer[RESOURCE_COUNT_MAX];
} resource = { 0, {0} }; // 生产者数据结构体


/*---------------------生产数据-----------------------------------------------*/
static void produce_item(int salt) 
{
    printf("produce item:\n");

    printf("%d", salt);
    resource.buffer[resource.cursor++] = salt;
    printf("\n");
}


/*---------------------消费数据----------------------------------------------*/
static void consume_item(void)
{
    printf("cosume item:\n");
    printf("%d\t", resource.buffer[--resource.cursor]);
    printf("\n");
}


/*---------------------生产者任务-------------------------------------------*/
void entry_task_producer(void *arg)
{
    size_t salt = 0;
    k_err_t err;

    while (1) {

        // 获取信号量 -1
        err = tos_sem_pend(&full, TOS_TIME_FOREVER);
        if (err != K_ERR_NONE) {
            continue;
        }

        // 获取互斥锁
        err = tos_mutex_pend(&buffer_locker);
        if (err != K_ERR_NONE) {
            continue;
        }

        produce_item(salt);  // 生产数据

        tos_mutex_post(&buffer_locker); // 释放互斥锁
        tos_sem_post(&empty);            // 释放empty+1
        tos_task_delay(1000);
        ++salt;                         // 数据更新
    }
}


/*---------------------消费任务------------------------------------------------*/
void entry_task_consumer(void *arg)
{
    k_err_t err;

    while (1) {

        // 获取信号量 -1
        err = tos_sem_pend(&empty, TOS_TIME_FOREVER); 
        if (err != K_ERR_NONE) {
            continue;  // GO TO  while(1)
        }

        // 获取互斥锁
        tos_mutex_pend(&buffer_locker);
        if (err != K_ERR_NONE) {
            continue; // GO TO  while(1)
        }

        consume_item();  // 消费数据

        tos_mutex_post(&buffer_locker); // 释放互斥锁
        tos_sem_post(&full);            // 释放full+1
        tos_task_delay(1000);
    }
}


/*-------------------------测试的应用函数入口--------------------------------*/
void application_sem(void *arg) // semaphore信号量测试
{
    // 创建mutex互斥
    tos_mutex_create(&buffer_locker);

    // 创建sem信号量
    tos_sem_create(&full, RESOURCE_COUNT_MAX);
    tos_sem_create(&empty, 0);

    // 创建task任务
    tos_task_create(&task_producer, "producer", entry_task_producer, NULL,
                            4, stack_task_producer, STK_SIZE_TASK_PRODUCER, 0);
    tos_task_create(&task_consumer, "consumer", entry_task_consumer, NULL,
                            4, stack_task_consumer, STK_SIZE_TASK_CONSUMER, 0);
}

 

 

在TencentOS-tiny\board\SWM320_DISCOVERY\BSP\Inc下的mcu_init.h增加如下

 

 

在main.c变更为:

/*

   必要头文件.h

 */
#include "cmsis_os.h"  // 原版本 V1.02
#include "mcu_init.h"



/*

  主main入口

*/
int main(void)
{
    /* PCB板初始化 */
    board_init();                              // mcu_init.h内实现

    /* 打印开机信息 */
    printf("Welcome to TencentOS v%s\r\n",TOS_VERSION);   // mcu_init.h内实现


    /* OS内核初始化 */
    osKernelInitialize();                      // 标准cmsis_os.h

    /* 用户Create */
    //application_entry(NULL);                   // hello world.c测试,mcu_init.h内关联
    //application_timer(NULL);                   // 软件定时器测试,mcu_init.h内关联
    //application_mutex(NULL);                   // mutex的测试
    application_sem(NULL);                       // semaphore信号量测试

    /* start */
    osKernelStart();                           // 开始OS内核调度
}

 

SWM32S开发板上仿真正常:

 

对于这个信号量,官方是用生产者和消费者进行测试的,这个思维新手很难理解,我个人觉得,用一个生活事情更好的讲述

信号量,在生活中我们开车去超市,到了停车厂如果有空车位,就可以开车进去占个车位,这个时候你只关心有没有停车位,

有几个停车位其实你并不关心,想想是不是?如果没有停车位,你就只能等一下了。。---》这就是获取信号量

你进到停车厂里面了,得找XX号停车位进行停车,如果俩位车主同时看到一个车位,哪就是谁近就是谁的位置了,很可能得继续找

其他的车XX号位置,----》这就是获取互斥锁 

当你开车离超市时,是先离开xx号停车位,再离开停车后门到马路回家,这就是 ---》这就是释放互斥锁、信号量

 

在这个生活例子中,门卫是生产者,因他只关心停车厂满没有满?满了就禁止车进来。车主是消费者,因为他只关心

有个XX号空车位。他们的焦点不同,一个关心FULL,一个关心empty。哎呀。不管怎么理解,这方面好像还是有点绕啊 !!

 

posted on 2021-08-22 17:57  木子剑  阅读(87)  评论(0编辑  收藏  举报