11.进程的同步与互斥

11.进程的同步与互斥

计数信号量及其初始化

和王道里面学的PV操作一摸一样,带个count变量,带个阻塞队列

//D:\code\x86\code\start\start\source\kernel\include\ipc\sem.h
#ifndef OS_SEM_H
#define OS_SEM_H#include "tools/list.h"/*** 进程同步用的计数信号量*/
typedef struct _sem_t {int count;				// 信号量计数list_t wait_list;		// 等待的进程列表
}sem_t;void sem_init (sem_t * sem, int init_count);#endif //OS_SEM_H

实现函数

//D:\code\x86\code\start\start\source\kernel\ipc\sem.c
#include "cpu/irq.h"
#include "core/task.h"
#include "ipc/sem.h"/*** 信号量初始化*/
void sem_init (sem_t * sem, int init_count) {sem->count = init_count;list_init(&sem->wait_list);
}

发送和等待信号

生产者消费者问题

//D:\code\x86\code\start\start\source\kernel\include\ipc\sem.h
void sem_wait (sem_t * sem); //相当于P操作
void sem_notify (sem_t * sem); //相当于V操作
int sem_count (sem_t * sem); //放回count

实现函数

//D:\code\x86\code\start\start\source\kernel\ipc\sem.c
/*** 申请信号量*/
void sem_wait (sem_t * sem) {irq_state_t  irq_state = irq_enter_protection(); //临界区的保护if (sem->count > 0) {sem->count--; //大于0的情况} else {// 从就绪队列中移除,然后加入信号量的等待队列task_t * curr = task_current(); //获取当前进程task_set_block(curr); //阻塞当前任务,移出就绪队列list_insert_last(&sem->wait_list, &curr->wait_node); //插入等待队列后面task_dispatch();}irq_leave_protection(irq_state);
}/*** 释放信号量*/
void sem_notify (sem_t * sem) {irq_state_t  irq_state = irq_enter_protection();if (list_count(&sem->wait_list)) {// 有进程等待,则唤醒加入就绪队列list_node_t * node = list_remove_first(&sem->wait_list);task_t * task = list_node_parent(node, task_t, wait_node);task_set_ready(task);task_dispatch();} else {sem->count++;}irq_leave_protection(irq_state);
}/*** 获取信号量的当前值*/
int sem_count (sem_t * sem) {irq_state_t  irq_state = irq_enter_protection();int count = sem->count;irq_leave_protection(irq_state);return count;
}

test函数

//如果一开始count给的初值为2,其他进程又没有释放这个资源,那么抢占资源的任务就会执行两次
//init.c
void init_task_entry(void) {int count = 0;for (;;) {sem_wait(&sem);log_printf("init task: %d", count++);// task_switch_from_to(&init_task, task_first_task());// sys_yield(); //自动放弃CPU让}
}
// 放在开中断前,以避免定时中断切换至其它任务,而此时信号量还未初始化
sem_init(&sem, 2);
结果

test2

//init.cint count = 0;for (;;) {log_printf("first task: %d", count++);// 发消息给init task,可以打印了sem_notify(&sem);sys_msleep(1000);// task_switch_from_to(task_first_task(), &init_task);        // sys_yield();}
结果

互斥锁

临界资源互斥fan

之前是应用自己操作开关中断,太危险了,我们把互斥部分封装起来

这很像简化版读者写者问题

但是这里同一进程可以给临界区上很多把锁

//D:\code\x86\code\start\start\source\kernel\include\ipc\mutex.h
#ifndef MUTEX_H
#define MUTEX_H#include "core/task.h"
#include "tools/list.h"/*** 进程同步用的计数信号量*/
typedef struct _mutex_t {task_t * owner; //锁的拥有者是谁int locked_count; //这把锁已经上锁了多少次,和信号量计数不一样list_t wait_list; //这把锁的等待队列
}mutex_t;void mutex_init (mutex_t * mutex); //初始化
void mutex_lock (mutex_t * mutex); //上锁
void mutex_unlock (mutex_t * mutex); //解锁#endif //MUTEX_H

实现函数

#include "cpu/irq.h"
#include "ipc/mutex.h"/*** 锁初始化*/
void mutex_init (mutex_t * mutex) { //初始化函数mutex->locked_count = 0; //上锁次数初始值为0mutex->owner = (task_t *)0; //拥有者清0list_init(&mutex->wait_list); //队列初始化
}
/*** 申请锁*/
void mutex_lock (mutex_t * mutex) {irq_state_t  irq_state = irq_enter_protection();task_t * curr = task_current();if (mutex->locked_count == 0) { //没有上锁的状态,是不是已经上锁了// 没有任务占用,占用之mutex->locked_count = 1; //上锁mutex->owner = curr; //归属} else if (mutex->owner == curr) { //已经上锁的状态,为自己,则二度上锁// 已经为当前任务所有,只增加计数mutex->locked_count++;} else { //其他进程申请// 有其它任务占用,则进入队列等待task_t * curr = task_current();task_set_block(curr); //阻塞起来(和王道里面一样没有外界资源,就阻塞起来)list_insert_last(&mutex->wait_list, &curr->wait_node); //放到这个锁的资源的等待队列里面task_dispatch(); //任务切换}irq_leave_protection(irq_state);
}/*** 释放锁*/
void mutex_unlock (mutex_t * mutex) { irq_state_t  irq_state = irq_enter_protection();// 只有锁的拥有者才能释放锁task_t * curr = task_current(); //获取当前进程if (mutex->owner == curr) { //锁都拥有者是不是自己if (--mutex->locked_count == 0) { //减到0才释放锁,自己上多道锁,自己也需要解锁n次才能打开这个锁// 减到0,释放锁mutex->owner = (task_t *)0;// 如果队列中有任务等待,则立即唤醒并占用锁if (list_count(&mutex->wait_list)) { //是不是有进程在等list_node_t * task_node = list_remove_first(&mutex->wait_list); //从等待队列移除task_t * task = list_node_parent(task_node, task_t, wait_node);task_set_ready(task); //插入就绪队列里面// 在这里占用,而不是在任务醒后占用,因为可能抢不到mutex->locked_count = 1;//把锁交出来mutex->owner = task; //owner换人了task_dispatch(); //任务切换}}}irq_leave_protection(irq_state);
}
实例使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/750099.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BswM模块配置指导

文章目录 BswM配置的分类自动配置:通信控制Rule:CC_ComMChannel_Rx自动配置:Ecu状态处理自动配置:模块初始化其他配置总结BswM模块是基础软件的模式管理模块,模式/状态控制都是由BswM模块进行,其实现的方式是通过 “请求-仲裁-执行”三步完成。本篇基于基本Can通信所用到…

string.h主要函数汇总

大家点击蓝色的连接就可以跳转查看了: strcpy,strncpy strchr strncmp strcmp strcat strncat strstr

2024计算机二级6

1.基本路径测试是属于白盒测试方法且是动态测试,静态测试不实际运行软件,主要通过人工进行分析。动态测试就是通常所说的上机测试,通过运行软件来检验软件中的动态行为和运行结果的正确性。百合测试的主要技术有逻辑覆盖测试、基本路径测试。…

UE5.1_自定义配置文件读取

UE5.1_自定义配置文件读取 读取配置文件时常规项目都会要求考虑的一个问题,然我接触过的UE类项目还真没考虑过,最近有个想法,奈何比较费劲,利用网上的教程跟进一下试试? 先基于Actor创建c++类(应该大家都会的吧),然后就是一下代码: MyConfig.h // Fill out your c…

CSS其他属性

文章目录 1. vertical-align1.1. 概念1.2. 常用值1.3. 作用1.4. 出现的情况一1.4.1. 原因1.4.2. 解决方案 1.5. 出现情况二1.5.1. 解决方案一1.5.2. 解决方案二1.5.3. 解决方案三 1.6. 出现情况三1.6.1. 原因1.6.2. 解决方案 2. 溢出效果2.1. 作用2.2. 属性名 3. 隐藏效果3.1. …

14双体系Java学习之数组

数组 ★小贴士 数组中保存固定数量的值,声明数组时需要制定数组中元素的类型,数组的长度在创建数组时设定。 保存数据的数据结构有很多,Java的标准函数库中就包含了许多复杂的数据结构,比如map、tree和set,以后会讲解的…

电脑那个部件坏了或者是哪个软件需要修复来看价钱

电脑维修价格表是多少? 价格取决于计算机的哪个部分损坏或哪个软件需要修复。 由于电脑中的部件非常多,而且会以各种奇怪的方式出现问题,下面我们就来看看具体的充电方法。 电脑维修价格表: 1. 重新安装系统。 安装XP系统通常需…

uniapp sqlite时在无法读取到已准备好数据的db文件中的数据

问题 {“code”:-1404,“message”:“android.database.sqlite.SQLiteException: no such table: user (Sqlite code 1): , while compiling: select * from user, (OS error - 2:No such file or directory),http://ask.dcloud.net.cn/article/282”} at pages/index/index.vu…

行走的机器人

题目描述 Bob 对机器人进行了编程,让它在平面迷宫中行走。 迷宫有一些障碍。 空单元格由字符"."表示,障碍物由"#"表示。 迷宫中只有一个机器人。 它的起始位置用字符"S"表示。 这个位置没有任何障碍。 迷宫中也只有一个…

<Linux> 线程的同步与互斥

目录 前言: 一、资源共享问题 (一)多线程并发访问 (二)临界资源与临界区 (三)“锁” 是什么 二、多线程抢票场景 (一)并发抢票 (二)并发访…

Segment Routing IPv6简介

定义 SRv6(Segment Routing IPv6,基于IPv6转发平面的段路由)是基于源路由理念而设计的在网络上转发IPv6数据包的一种协议。SRv6通过在IPv6报文中插入一个路由扩展头SRH(Segment Routing Header),在SRH中压…

Ubuntu下安装microk8s用代理解决无法拉取镜像问题

首先安装microk8s: sudo snap install microk8s --classic得到输出: microk8s (1.28/stable) v1.28.7 from Canonical✓ installed设置 K8s 命令别名(alias) MicroK8s 支持的命令中,我们会相对高频的使用 microk8s.kubectl 这个…

渗透测试与HTTP中的PUT请求

PUT 请求用于向服务器更新指定资源,可以理解为对服务器上的资源进行修改操作。使用 PUT 请求方式会覆盖原有的资源内容,因此需要谨慎使用。 在渗透测试中,有可能服务端会暴露PUT请求的api,如修改用户权限的api,例如HT…

蓝桥杯练习系统(算法训练)ALGO-971 比较

资源限制 内存限制:256.0MB C/C时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s 问题描述 给出一个n长的数列,再进行m次询问,每次询问询问两个区间[L1,R1],[L2,R2],  …

HarmonyOS NEXT应用开发—Grid和List内拖拽交换子组件位置

介绍 本示例分别通过onItemDrop()和onDrop()回调,实现子组件在Grid和List中的子组件位置交换。 效果图预览 使用说明: 拖拽Grid中子组件,到目标Grid子组件位置,进行两者位置互换。拖拽List中子组件,到目标List子组件…

数据可视化-ECharts Html项目实战(1)

在之前的文章中,我们学习了如何安装Visual Studio Code并下载插件,想了解的朋友可以查看这篇文章。同时,希望我的文章能帮助到你,如果觉得我的文章写的不错,请留下你宝贵的点赞,谢谢。 安装 Visual Studio…

一个服务出现fullgc正常吗 少量的fullgc会影响系统的稳定性吗

在Java应用的运行过程中,发生Full GC是正常的,因为它是JVM垃圾回收机制的一部分。Java虚拟机会定期进行垃圾回收以回收不再被使用的对象所占用的内存。然而,频繁的Full GC或者过长的GC暂停时间是不理想的,因为它会导致应用程序在垃…

网络管理基础

Linux网络管理 1.网络管理概念 网络接口和名称 :网卡 ip地址 网关 主机名称 路由2.管理工具 net-tools: #安装包 ifconfig netstat 准备要废掉了。iproute: #安装包 ip #提供ip命令3.认识网卡 lo网卡 :本地回环网卡,本机上的服务自己访问自…

MySQL安装(Mac系统)

首先要删除本机原有的mysql 停止MySQL服务 sudo /usr/local/mysql/support-files/mysql.server stop不放心可以使用以下命令查询并杀死进程 ps aux | grep mysqld sudo kill <PID>再次尝试停止服务 sudo /usr/local/mysql/support-files/mysql.server stop卸载MySQL&…

【python开发】并发编程(上)

并发编程&#xff08;上&#xff09; 一、进程和线程&#xff08;一&#xff09;多线程&#xff08;二&#xff09;多进程&#xff08;三&#xff09;GIL锁 二、多线程开发&#xff08;一&#xff09;t.start()&#xff08;二&#xff09;t.join()&#xff08;三&#xff09;t.…