UCOS Operating System - Semaphore Experiment (10)

UCOS operating system

1. Direct access to the shared resource area

As mentioned above, semaphores are mainly used to access shared resources and perform task synchronization. Here we will do an experiment of directly accessing shared resources to see what the consequences will be.

Create 3 tasks, task A is used to create the other two tasks, and task A will be deleted after it is executed once. Both task B and task C can access the shared resource D, and tasks B and C directly access the shared resource D. Observe the consequences of accessing the shared resource directly.

u8 share_resource[30]; //共享资源区
//任务 1 的任务函数
void task1_task(void *p_arg)
{
    
    
OS_ERR err;
u8 task1_str[]="First task Running!";
while(1)
{
    
    
printf("\r\n 任务 1:\r\n");
LCD_Fill(0,110,239,319,CYAN);
memcpy(share_resource,task1_str,sizeof(task1_str)); //向共享资源区拷贝数据 (1)
delay_ms(200);
printf("%s\r\n",share_resource); //串口输出共享资源区数据
LED0 = ~LED0;
OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err); //延时 1s
} }
//任务 2 的任务函数
void task2_task(void *p_arg)
{
    
    
u8 i=0;
OS_ERR err;
u8 task2_str[]="Second task Running!";
while(1)
{
    
    
printf("\r\n 任务 2:\r\n");
LCD_Fill(0,110,239,319,BROWN);
memcpy(share_resource,task2_str,sizeof(task2_str));//向共享资源区拷贝数据 (2)
delay_ms(200);
printf("%s\r\n",share_resource); //串口输出共享资源区数据
LED1 = ~LED1;
OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err); //延时 1s
}

(1) Task 1 copies the data "First task Running!" to the shared resource area, then delays it for 200ms, and outputs
the data copied to the shared resource area through the serial port, that is, "First task Running!".
(2) Task 2 also copies the data "Second task Running!" to the shared resource area, with the same delay of 200ms, and
copies the data to the shared resource area through the serial port, and outputs "Second task Running!". Both task 1 and task 2 use the shared resource share_resource. We use the function delay_ms() for delay in task 1 and task 2. The delay_ms() function will cause task switching, and our access to shared resources Without any protection, unexpected results will inevitably occur.
insert image description here
This is not the result we want. The following is our ideal result.
insert image description here
After task 1 copies the data "First task Running!" to share_resource, the task switch is performed because of the delay_ms() function system. Task 2 starts to run. At this time, task 2 copies the data "Second task Running!" to share_resource. Task 2 also switches tasks due to the delay_ms() function, and task 1 continues to run, but the share_resource has been modified to "Second task Running!" task Running!" Therefore, the output will be different from what we expected, which will lead to the occurrence of errors. This is the problem caused by the multi-task shared resource area!

Second, use semaphore to access the shared resource area experiment

In the above experiment, we did not protect the access to share_resource, which led to the occurrence of errors. We can avoid this problem by using semaphore to access the shared resource area.

OS_SEMMY_SEM; //定义一个信号量,用于访问共享资源
//创建一个信号量
OSSemCreate ((OS_SEM* )&MY_SEM, //指向信号量
 (CPU_CHAR* )"MY_SEM", //信号量名字
 (OS_SEM_CTR )1, //信号量值为 1
 (OS_ERR* )&err);
 //任务 1 的任务函数
void task1_task(void *p_arg)
{
    
    
OS_ERR err;
u8 task1_str[]="First task Running!";
while(1)
{
    
    
printf("\r\n 任务 1:\r\n");
LCD_Fill(0,110,239,319,CYAN);
OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); //请求信号量(1)
memcpy(share_resource,task1_str,sizeof(task1_str)); //向共享资源区拷贝数据
delay_ms(200);
printf("%s\r\n",share_resource); //串口输出共享资源区数据
OSSemPost (&MY_SEM,OS_OPT_POST_1,&err); //发送信号量 (2)
LED0 = ~LED0;
OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err); //延时 1s
} 
}
//任务 2 的任务函数
void task2_task(void *p_arg)
{
    
    
OS_ERR err;
u8 task2_str[]="Second task Running!";
while(1)
{
    
    
printf("\r\n 任务 2:\r\n");
LCD_Fill(0,110,239,319,BROWN);
OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); //请求信号量(3)
memcpy(share_resource,task2_str,sizeof(task2_str)); //向共享资源区拷贝数据
delay_ms(200);
printf("%s\r\n",share_resource); //串口输出共享资源区数据
OSSemPost (&MY_SEM,OS_OPT_POST_1,&err); //发送信号量 (4)
LED1 = ~LED1;
OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err); //延时 1s
} }

(1) Task 1 wants to access the shared resource share_resource, so call the function OSSemPend() to request the semaphore.
(2) Task 1 After using the shared resource share_resource, call the OSSemPost() function to release the semaphore.
(3) Same as (1)
(4) Same as (2)
insert image description here
Using semaphore can completely avoid this problem.

3. Task synchronization experiment

Semaphore is now more used to achieve task synchronization and synchronization between tasks and ISR.
insert image description here
A small flag represents the semaphore. The value N next to the small flag is the semaphore count value, indicating the cumulative value of the number of times the semaphore is released, ISR The semaphore can be released multiple times, and the number of releases will be recorded as N. In general, N is used to indicate how many semaphores are available initially. A small hourglass next to a task waiting for a semaphore indicates that the waiting task can set a timeout. Timeout means that the task will only wait for a semaphore for a certain period of time. If the semaphore is not waited for within this period, UCOSIII will place the task in the ready list and return an error code. The initial value is 0, indicating that the event has not yet occurred. During initialization, the initial value of N can also be set to a value greater than zero.

Experimental design:
Create 3 tasks, task A is used to create two other tasks and a semaphore with an initial value of 0, task C
must obtain the consent of task B to perform an operation.
Answer: This problem is obviously a problem of task synchronization. A semaphore with an initial value of 0 is set between the two tasks to realize
the cooperation of the two tasks. Task B expresses approval or not by sending a semaphore, and task C always requests the semaphore. When the semaphore is greater than
1, task C can perform the next operation.

//任务 1 的任务函数
void task1_task(void *p_arg)
{
    
    
u8 key;
OS_ERR err;
while(1)
{
    
    
key = KEY_Scan(0); //扫描按键
if(key==WKUP_PRES)
{
    
    
OSSemPost(&SYNC_SEM,OS_OPT_POST_1,&err);//发送信号量 (1)
LCD_ShowxNum(150,111,SYNC_SEM.Ctr,3,16,0); //显示信号量值 (2)
}
OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err); //延时 10ms
} }
//任务 2 的任务函数
void task2_task(void *p_arg)
{
    
    
u8 num;
OS_ERR err;
while(1)
{
    
    
//释放信号量
OSSemPend(&SYNC_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); (3)
num++;
LCD_ShowxNum(150,111,SYNC_SEM.Ctr,3,16,0); //显示信号量值
LCD_Fill(6,131,233,313,lcd_discolor[num%14]); //刷屏
LED1 = ~LED1;
OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err); //延时 1s
} }

(1) When the KEY_UP key is pressed, call the OSSemPost() function to send a semaphore.
(2) The field Ctr of the semaphore SYNC_SEM is used to record the semaphore value. Every time we call the OSSemPost() function
, the Ctr field will increase by one. Here we display the value of Ctr on the LCD to observe the change of Ctr.
(3) Task 2 requests the semaphore SYNC_SEM. If the semaphore is requested, the code below task 2 will be executed.
If it is not requested, the function will be blocked all the time. When the function OSSemPend() is called to request the semaphore successfully,
the field Ctr of SYNC_SEM will be decremented by one until it becomes 0.

Since the initial value of our newly created semaphore SYNC_SEM is 0, after booting, task 2 will be blocked because the semaphore cannot be requested
insert image description here
. From the figure, we can see that since the initial value of the semaphore SYNC_SEM is 0, the signal of SYNC_SEM The magnitude value is displayed as 0, and task 2 blocks. When we press the KEY_UP key, the semaphore will be sent, and the value of SYNC_SEM will change (increase). When we press the KEY_UP key several times
insert image description here
, the value of the semaphore SYNC_SEM is 3, indicating that task 2 can request the semaphore SYNC_SEM three times. . Task 2 will request a semaphore SYNC_SEM every 1s until the semaphore value of SYNC_SEM is 0. Since task 2 cannot request the semaphore, task 2 will block.
insert image description here
Press it again to continue execution.

About mutex semaphore and priority inversion, just read my previous blog, which is very detailed.

Guess you like

Origin blog.csdn.net/qq_51963216/article/details/123923768