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通信所用到…

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系统通常需…

<Linux> 线程的同步与互斥

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

Segment Routing IPv6简介

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

蓝桥杯练习系统(算法训练)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…

网络管理基础

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.…

Golang协程详解

一.协程的引入 1.通过案例文章引入并发,协程概念 见:[go学习笔记.第十四章.协程和管道] 1.协程的引入,调度模型&#xff0c;协程资源竞争问题 通过上面文章可以总结出Go并发编程原理: 在一个处理进程中通过关键字 go 启用多个协程&#xff0c;然后在不同的协程中完成不同的子任…

Elasticsearch 主副分片切换过程中对业务写入有影响吗

&#x1f34a;&#x1f349;&#x1f34b; 先说下结论&#xff0c;只要集群中的工作节点过半&#xff0c;有候选的master节点&#xff0c;挂掉的节点中不同时包含索引的主分片和副分片&#xff0c;那么ES是可以做到让业务无感知的进行主副分片切换的。 蓝胖子会先讲解下ES集群写…

Spring Cloud Alibaba微服务从入门到进阶(六)(声明式HTTP客户端-Feign)

Feign是Netflix开源的声明式HTTP客户端&#xff08;只要声明一个接口&#xff0c;Feign就会通过你定义的接口自动给你构造请求的目标地址&#xff0c;并帮助你请求&#xff09; 用Feign重构前面RestTemplate方式的服务间调用 想回顾一下RestTemplate调用 加依赖 项目集成Feig…

最细节操作 Linux LVM 逻辑卷管理

Linux LVM&#xff08;逻辑卷管理&#xff09; 周末愉快&#xff0c;今天带大家实战一下LVM! 一、LVM理论 LVM&#xff0c;即Logical Volume Manager&#xff0c;逻辑卷管理器&#xff0c;是一种硬盘的虚拟化技术&#xff0c;可以允许用户的硬盘资源进行灵活的调整和动态管理…

2025武忠祥考研数学,视频百度网盘+基础全程课程PDF

“得数学者的天下”&#xff0c;25考研首先要开始的就是数学复习&#xff0c;而数学复习首先要开始的必然是高数&#xff01; 很多同学选择了跟着武忠祥老师学习高数&#xff0c;但是具体要怎么学&#xff1f;用什么书&#xff1f;怎么刷题&#xff1f;快来看看以 下的武忠祥…

广东省活动积温空间分布数据

广东省是中国大陆南端沿海的一个省份&#xff0c;位于南岭以南&#xff0c;属于东亚季风区&#xff0c;从北向南分别为中亚热带、南亚热带和热带气候&#xff0c;是中国光、热和水资源最丰富的地区之一。年平均气温约为19℃~24℃&#xff0c;1月平均气温约为16℃~19℃&#xff…

【运维】StarRocks数据迁移到新集群(针对于集群互通、不互通的情况)

文章目录 一. 迁移整体思路1. 对于新旧集群互通的情况2. 对于新旧集群不互通的情况 二、迁移过程&#xff08;两个集群互通的情况&#xff09;1. 备份过程1.1. 通过mysqlclient与starrocks进行关联1.2. 创建仓库与minio建立联系1.3. 备份数据到minio 2. 迁移过程2.1. 通过mysql…

YOLOv9改进策略:注意力机制 | 极化自注意力Polarized Self-Attention,效果秒杀CBAM、SE

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a;本文针对Pixel-wise regression的任务&#xff0c;提出了一种更加精细的双重注意力机制——极化自注意力&#xff08;Polarized Self-Attention&#xff09;&#xff0c;效果优于CBAM、SE等经典注意力。 yolo…