UCOS操作系统

文章目录

  • UCOS操作系统
  • 一、直接访问共享资源区
  • 二、使用信号量访问共享资源区实验
  • 三、任务同步实验

一、直接访问共享资源区

前面提过信号量主要用于访问共享资源和进行任务同步,这里我们先做一个直接访问共享资源的实验,看看会带来什么后果。

创建 3 个任务,任务 A 用于创建其他两个任务,任务 A 执行一次后就会被删除掉。任务 B 和任务 C 都可以访问作为共享资源 D,任务 B 和 C 对于共享资源 D 是直接访问的,观察直接访问共享资源会造成什么要的后果。

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) 任务 1 向共享资源区拷贝数据“First task Running!”,然后延时 200ms,通过串口输出
拷贝到共享资源区中的数据,既输出“First task Running!”。
(2) 任务 2 也向共享资源区中拷贝数据“Second task Running!”,同样延时 200ms,并通过
串口拷贝到共享资源区中的数据,既输出“Second task Running!”。任务 1 和任务 2 都使用了共享资源 share_resource,我们在任务 1 和任务 2 中都是使用了函数 delay_ms()进行延时,delay_ms()函数是会引起任务切换的,而我们对于共享资源的访问没有进行任何的保护,势必会造成意想不到的结果发生。

这并不是我们想要的结果,下面是我们理想的结果

在任务 1 向 share_resource 拷贝数据“First task Running!”以后就因为delay_ms()函数系统进行了任务切换。任务 2 开始运行,这时任务 2 又向 share_resource 拷贝了数据“Second task Running!”,任务 2 也因为 delay_ms()函数发生任务切换,任务 1 接着运行,但是这是 share_resource 已经被被修改为 “Second task Running!”因此输出就会和我们预计的不一样了,从而导致错误的发生,这个就是多任务共享资源区带来的问题!

二、使用信号量访问共享资源区实验

在上面的实验中我们对于 share_resource 的访问并没有进行保护,从而导致了错误的发生我们使用信号量来进行共享资源区的访问就可以避免这个问题。

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) 任务 1 要访问共享资源 share_resource,因此调用函数 OSSemPend()来请求信号量。
(2) 任务 1 使用完共享资源 share_resource,调用 OSSemPost()函数释放信号量。
(3) 同(1)
(4) 同(2)

使用信号量完全可以避免这个问题。

三、任务同步实验

信号量现在更多的被用来实现任务的同步以及任务和 ISR 间的同步

用一个小旗子代表信号量,小旗子旁边的数值 N 为信号量计数值, 表示发布信号量的次数累积值,ISR 可以多次发布信号量,发布的次数会记录为 N。一般情况下,N 的来表示初始情况下有多少信号量可用。等待信号量的任务旁边的小沙漏表示等待任务可以设定超时时间。超时的意思是该任务只会等待一定时间的信号量,如果在这段时间内没有等到信号量,UCOSIII 就会将任务置于就绪表中,并返回错误码。初始值是 0,表示事件还没有发生过。在初始化时,也可以将 N 的初值设为大于零的某个值。

实验设计:
创建 3 个任务,任务 A 用于创建其他两个任务和一个初始值为 0 的信号量,任务 C
必须征得任务 B 的同意才能执行一次操作。
答:这个问题显然是一个任务同步的问题,在两个任务之间设置一个初值为 0 的信号量来实现
两个任务的合作。任务 B 通过发信号量表示同意与否,任务 C 一直请求信号量,当信号量大于
1的时候任务C才能执行接下来的操作。

//任务 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) 当 KEY_UP 键按下的时候调用 OSSemPost()函数发送一次信号量。
(2) 信号量 SYNC_SEM 的字段 Ctr 用来记录信号量值,我们每调用一次 OSSemPost()函数
Ctr 字段就会加一,这里我们将 Ctr 的值显示在 LCD 上,来观察 Ctr 的变化。
(3) 任务 2 请求信号量 SYNC_SEM,如果请求到信号量的话就会执行任务 2 下面的代码,
如果没有请求到的话就会一直阻塞函数。当调用函数 OSSemPend()请求信号量成功的话,
SYNC_SEM 的字段 Ctr 就会减一,直到为 0。

由于我们新建的信号量 SYNC_SEM的初始值为 0,因此在开机以后任务 2 会由于请求不到信号量而阻塞

从图中我们可以看出,由于信号量 SYNC_SEM 的初始值为 0,因此 SYNC_SEM 的信号量值显示为 0,并且任务 2 阻塞。当我们按下 KEY_UP 键以后就会发送信号量,SYNC_SEM的值就会变化(增加),我们多按几次 KEY_UP 键

此时信号量 SYNC_SEM 的值为 3,说明任务 2 可以请求 3 次信号量 SYNC_SEM。任务 2 每隔 1s 就会请求一起信号量 SYNC_SEM,直到 SYNC_SEM 的信号量值为 0,由于任务 2 请求不到信号量了,因此任务 2 就会阻塞

再次按下就会继续执行

关于互斥信号量和优先级反转看我之前的博客即可,写的很详细。

UCOS操作系统——信号量实验(十)相关推荐

  1. UCOS操作系统——信号量与互斥信号量(九)

    UCOS操作系统 文章目录 UCOS操作系统 一.信号量简介 1.二进制信号量 2.计数型信号量 二.使用信号量 1.相关API函数 2.OSSemCreate()创建信号量 3.OSSemPend( ...

  2. 操作系统—信号量实验项目

    信号量实验项目: 桌子上有一个能盛得下5个水果的空盘子,爸爸不停地向盘子中放入苹果或者桔子,儿子不停地从盘子中取出桔子享用,女儿不停的从盘子中取出苹果享用.规定三人不能同时从盘子中取放水果.试用信号量 ...

  3. UCOS操作系统——事件标志组(十四)

    UCOS操作系统 文章目录 UCOS操作系统 前言 一.事件标志组 二.相关函数 1.创建事件标志组 2. 等待事件标志组 3.向事件标志组发布标志 三.事件标志组实验 前言 前面我们提到过可以使用信 ...

  4. 操作系统真象还原实验记录之实验十二:实现ASSERT

    操作系统真象还原实验记录之实验十二:实现ASSERT,通过makefile完成编译 对应书P367 第8.2节 1.相关基础知识 见书 2.实验代码 完成了开关中断函数.实现assert断言函数用于调 ...

  5. 操作系统课程设计---实验十 简单shell命令行解释器的设计与实现

    实验十 简单shell命令行解释器的设计与实现 完整课程设计源码及其报告查看:陈陈的操作系统课程设计 1.实验目的 本实验主要目的在于进一步学会如何在 Linux 系统下使用进程相关的系统调用,了解 ...

  6. 虚拟机dhcp服务器怎么检验,实验十二虚拟机上DHCP服务器的配置和验证.doc

    实验十二 虚拟机上DHCP服务器的配置与验证 一.实验目的 了解DHCP的基本概念和服务器的新特性 掌握DHCP服务器的安装与配置 掌握DHCP的运行方式 掌握DHCP客户机的设置 掌握ipconfi ...

  7. 进程同步算法实现实验报告Linux,操作系统进程同步实验报告.doc

    操作系统进程同步实验报告 实验三:进程同步实验 一.实验任务: (1)掌握操作系统的进程同步原理: (2)熟悉linux的进程同步原语: (3)设计程序,实现经典进程同步问题. 二.实验原理: (1) ...

  8. 操作系统权限提升(十五)之绕过UAC提权-基于白名单DLL劫持绕过UAC提权

    系列文章 操作系统权限提升(十二)之绕过UAC提权-Windows UAC概述 操作系统权限提升(十三)之绕过UAC提权-MSF和CS绕过UAC提权 操作系统权限提升(十四)之绕过UAC提权-基于白名 ...

  9. ZUCC_操作系统原理实验_Lab9进程的通信消息队列

    lab9进程的通信–消息队列 一.两个进程并发执行,通过消息队列,分别进行消息的发送和接收 1.代码: //接受消息 #include<stdio.h> #include<stdli ...

  10. ZUCC_操作系统原理实验_实验九 消息队列

    操作系统原理实验报告 课程名称 操作系统原理实验 实验项目名称 实验九 消息队列 实验目的 了解 Linux 系统的进程间通信机构 (IPC): 理解Linux 关于消息队列的概念: 掌握 Linux ...

最新文章

  1. Hibernate4组件映射
  2. 属于你们的“礼仪小课堂”
  3. it编年史_Java的编年史和低延迟
  4. Spring 4 MVC 单元测试例子
  5. 关于android开发时,发生Error infalting classa com.baidu.mapapi.map.MapView的解决办法
  6. 查询使用NoLock
  7. 万能文件在线预览项目,开源!
  8. 【大学生】做‘心机’大学生,深度高效挖掘有效人脉
  9. ES6新特性_Promise实践练习-多个文件内容读取---JavaScript_ECMAScript_ES6-ES11新特性工作笔记028
  10. 【洛谷P1800】software_NOI导刊2010提高(06)
  11. 最后1天!阿里云双11拼团入官方热荐团直享最低折扣!还有机会瓜分百万现金!...
  12. 安装pytorch-metric-learning
  13. python函数进阶小结_Python 函数3000字使用总结
  14. 华为 oj java题库_华为OJ 201301 JAVA题目0-1级
  15. BAT智能硬件布局 争搭平台卡位各异
  16. CAD绘图的基本步骤和重点
  17. 网页标题前面的logo怎么设置
  18. 2022-2028年全球与中国粮食种植行业市场深度调研及投资预测分析
  19. 挂载NTFS分区导致Docker容器无法启动,Exited (137)错误
  20. geoserver配置SQL图层 cql_filter模糊查询

热门文章

  1. 怎样鉴别台式计算机主板型号,如何识别联想主板型号
  2. JDK 和 JRE 有什么区别?面试篇(第一天)
  3. 全国所有省份、城市的JSON
  4. Linux 2.6内核配置说明
  5. 通信接口:UART、I2C、SPI、TTL、RS232、RS422、RS485、CAN、USB
  6. 安卓微信本地数据库解密
  7. Springboot毕设项目眼镜店管理系统1m12ajava+VUE+Mybatis+Maven+Mysql+sprnig)
  8. 家庭电信网弄外网唤醒并远程内网电脑
  9. TIA安装GSD文件
  10. 清空数据库里面所有表的数据的语句