同步 -- 信号量

news2024/11/26 7:43:08

 本篇文章基于Linux-6.5源码

建议:搭配Linux源码观看更佳

struct semaphore {
    raw_spinlock_t        lock; // 保护信号量的自旋锁
    unsigned int        count; // 最大同时可访问临界区的进程数量
    struct list_head    wait_list; // 等待队列,wait_list指向队列末尾
};

struct semaphore_waiter {
	struct list_head list; //表示当前任务在等待队列中的节点指针
	struct task_struct *task; //
	bool up; //任务等待状态,true或false
};

API接口

sema_init

#define __SEMAPHORE_INITIALIZER(name, n)				\
{									\
	.lock		= __RAW_SPIN_LOCK_UNLOCKED((name).lock),	\
	.count		= n,						\
	.wait_list	= LIST_HEAD_INIT((name).wait_list),		\
}

//初始化信号量sem,sem->count = val。
static inline void sema_init(struct semaphore *sem, int val)
{
	static struct lock_class_key __key;
	*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
	lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
}

down

获取信号量,获取成功,则sem->count -1。获取失败,将进程加入等待队列,开始休眠,直到已获得信号量的进程释放信号量时,会唤醒等待队列的进程。进程睡眠时,状态是TASK_UNINTERRUPTIBLE,表示睡眠过程不接受信号打断,

void __sched down(struct semaphore *sem)
{
	unsigned long flags;

	might_sleep();
    //加锁,将count操作
	raw_spin_lock_irqsave(&sem->lock, flags);
	if (likely(sem->count > 0))
		sem->count--;
	else
        //如果count已为0,则获取失败
		__down(sem); 
	raw_spin_unlock_irqrestore(&sem->lock, flags);
}
EXPORT_SYMBOL(down);

static noinline void __sched __down(struct semaphore *sem)
{
	__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}

static inline int __sched ___down_common(struct semaphore *sem, long state,
								long timeout)
{
	struct semaphore_waiter waiter;
    //把当前进程加入到信号量sem的等待队列wait_list中
	list_add_tail(&waiter.list, &sem->wait_list);
	waiter.task = current; //记录当前任务的task_struct
	waiter.up = false; //false表示在等待
    //循环
	for (;;) {
		if (signal_pending_state(state, current))
			goto interrupted;
		if (unlikely(timeout <= 0))
			goto timed_out;
		__set_current_state(state); //设置当前进程状态为不可中断状态
		raw_spin_unlock_irq(&sem->lock);
		timeout = schedule_timeout(timeout); //主动调度,等待timeout或者被wake_up
		raw_spin_lock_irq(&sem->lock);
        
        //当已获得信号量的进程释放时,会唤醒等待队列的进程,此时up为ture,跳出循环
		if (waiter.up)
			return 0;
	}

 timed_out:
	list_del(&waiter.list);
	return -ETIME;

 interrupted:
	list_del(&waiter.list);
	return -EINTR;
}

up

释放信号量:如果等待队列为空,说明没有任务在等待,则直接将count++。如果不为空,唤醒队列头部的任务,并出队。

void __sched up(struct semaphore *sem)
{
	unsigned long flags;

	raw_spin_lock_irqsave(&sem->lock, flags);
    //如果等待队列为空,说明没有任务在等待,则直接将count++
	if (likely(list_empty(&sem->wait_list)))
		sem->count++;
	else
        //否则,出队等待队列中的任务,并唤醒
		__up(sem);
	raw_spin_unlock_irqrestore(&sem->lock, flags);
}
EXPORT_SYMBOL(up);

static noinline void __sched __up(struct semaphore *sem)
{
    //获得队列头的任务
	struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
						struct semaphore_waiter, list);
	list_del(&waiter->list); //出队
	waiter->up = true; //表示不再等待
	wake_up_process(waiter->task); //唤醒任务
}

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

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

相关文章

linux 磁盘命令之du和df命令

du相关的命令: du -ah 显示所有目录或文件所占空间 du -KG 显示所有目录或文件所占空间 块大小K为单位 du -BM 显示所有目录或文件所占空间 块大小M为单位 du -BG 显示所有目录或文件所占空间 块大小G为单位du -sh [目录名] 返回该目录的大小 du -sm [文件夹] 返回该文…

5.2 磁盘CRC32完整性检测

CRC校验技术是用于检测数据传输或存储过程中是否出现了错误的一种方法&#xff0c;校验算法可以通过计算应用与数据的循环冗余校验&#xff08;CRC&#xff09;检验值来检测任何数据损坏。通过运用本校验技术我们可以实现对特定内存区域以及磁盘文件进行完整性检测&#xff0c;…

Java“牵手”天猫商品列表页数据采集+天猫商品价格数据排序,天猫API接口申请指南

天猫开放平台接口获取商品列表和详情数据&#xff0c;具体步骤如下&#xff1a; 在开放平台注册并创建一个应用&#xff0c;获取到 App Key 和 App Secret等信息。使用获取到的信息进行签名和认证&#xff0c;获取 Access Token。调用开放平台提供的接口&#xff0c;传入商品 …

PM3398B-6P-1–3P-E 借助物联网和人工智能解决方案

PM3398B-6P-1–3P-E 借助物联网和人工智能解决方案 油砂中的卡车发动机捕获大量数据&#xff0c;如振动、温度、压力和吞吐量等参数。但是这些数据大部分都没有被使用。借助物联网和人工智能解决方案&#xff0c;您可以轻松利用这些数据获得有用的见解。这些见解有助于您提高发…

1.wifi开发,wifi连接初次连接电脑没有识别,搭建环境

wifi连接初次连接电脑没有识别 1.不识别可能是线的问题&#xff0c;即使wifi的灯亮了&#xff0c;虽然串口却没有找到。所以解决方法就是重新来一个usb的线 一。初步使用 &#xff08;1&#xff09;使用ESP烧写工具&#xff08;选择esp8266&#xff09; &#xff08;2&#xf…

TienChin 渠道管理-添加渠道

在我们平时新建一个全新的 Java 类&#xff0c;这个类需要存放的包不存在&#xff0c;可以使用如下的方式进行创建&#xff1a; 含义就是说&#xff0c;将 ChannelVO 这个类放在 vo 这个包当中&#xff0c;如果存在则不创建&#xff0c;存在就将新建的类放入其中。 ChannelVO /…

2000-2018年各省能源消费和碳排放数据

2000-2018年各省能源消费和碳排放数据 1、时间&#xff1a;2000-2018年 2、范围&#xff1a;30个省市 3、指标&#xff1a;id、year、ENERGY、COAL、碳排放倒数*100 4、来源&#xff1a;能源年鉴 5、指标解释&#xff1a; 2018年碳排放和能源数据为插值法推算得到 碳排放…

SpringBoot接口中如何直接返回图片数据

SpringBoot接口中如何直接返回图片数据 目录 接口直接返回图片数据 起因 类似这种 根据个人经验 优雅的实现图片返回 接口直接返回图片数据 起因 最近在做涉及到分享推广的业务&#xff0c;需要由业务员分享二维码进入推广页面&#xff0c;由于是新项目&#xff0c;前期…

Vue.js基本语法上

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《springMvc使用》 ⛺️ 生活的理想&#xff0c;为了不断更新自己 ! 目录 1.插值 1.1 文本 1.2 v-v-html 1.3 数据双向绑定数据(v-model) 1.4 属性&#xff…

fork函数

二.fork函数 2.1函数原型 fork()函数在 C 语言中的原型如下&#xff1a; #include <unistd.h>pid_t fork(void);其中pid_t是一个整型数据类型&#xff0c;用于表示进程ID。fork()函数返回值是一个pid_t类型的值&#xff0c;具体含义如下&#xff1a; 如果调用fork()的…

Vue3 菜鸟入门(一)超详细:介绍、安装、打包、创建项目、目录结构、起步等

【学习笔记】Vue3 菜鸟入门&#xff08;一&#xff09;超详细&#xff1a;介绍、安装、打包、创建项目、目录结构、起步等 关键词&#xff1a;Vue 、Vue 3、Java、Spring Boot、Idea、数据库、一对一、培训、教学本文主要内容含Vue3介绍、安装、打包、创建项目、目录结构、起步…

避雷器雷击计数器检验

试验目的 由于密封不良&#xff0c; 放电计数器在运行中可能进入潮气或水分&#xff0c; 使内部元件锈蚀&#xff0c;导致计数器不能正确动作&#xff0c; 因此需定期试验以判断计数器是否状态良好、 能否正常动作&#xff0c; 以便总结运行经验并有助于事故分析。 带有泄漏电…

[论文阅读] SADGA: Structure-Aware Dual Graph Aggregation Network for Text-to-SQL

“SADGA: Structure-Aware Dual Graph Aggregation Network for Text-to-SQL” 是一篇 text2sql 领域的论文&#xff0c;发布于 NeurIPS 2021。 原文链接&#xff1a;https://arxiv.org/abs/2111.00653 项目代码链接&#xff1a;https://github.com/DMIRLAB-Group/SADGA 总体…

exev函数族

一.exev函数族 1.1功能 exec()函数族的主要功能是在当前进程中运行一个新的程序。使用这些函数可以实现以下功能&#xff1a; 程序替换&#xff08;Program Replacement&#xff09;&#xff1a;调用exec()函数后&#xff0c;当前进程的代码和数据会被新程序的代码和数据替换…

【JDK 8-集合框架】5.4 allMatch 和 anyMatch 函数

一、allMatch 函数 二、anyMatch 函数 三、其它函数学习 四、实战 > 执行结果 一、allMatch 函数 检查是否 匹配所有元素&#xff0c;返回 true 二、anyMatch 函数 检查是否 至少匹配一个元素&#xff0c;返回 true 三、其它函数学习 看源码 入参&#xff0c;返回值…

【ElementUI】ElementUI Tooltip 根据内容判断是否显示、文字提示自定义样式

【ElementUI】ElementUI Tooltip 根据内容判断是否显示、文字提示自定义样式 封装组件自定义内容 <template><span v-if"[, null, undefined].indexOf(content) -1"><el-tooltip :content"content" effect"light" placement&q…

ENVI IDL:OMI-NO2产品均值计算与可视化(附Python代码)-年、季、月均值计算

目录 01 实验题目 02 我的IDL代码 03 实验给定IDL代码 04 Python代码实现 4.1 我的Python代码 4.2 实验给定Python代码 01 实验题目 计算/coarse_data/chapter_2/NO2/目录下所有OMI-NO2产品数据集ColumnAmountNO2TropCloudScreened的月均值、季均值、年均值&#xff0c;并…

风控基础——MOB、Vintage是什么?

▍Vintage背景 Vintag一词最初来源于葡萄酒业 。由于每年采摘的葡萄会受到日照、气温、降水等因素的影响&#xff0c;最终酿造的葡萄酒品质会存在差异。在窖藏一定年份后&#xff0c;葡萄酒的品质将趋于稳定&#xff0c;也就是品质成熟&#xff0c;这段年份数被称为成熟期。表…

广州华锐互动:利用VR复原文化遗址,沉浸式体验历史文物古迹的魅力

在过去的几十年里&#xff0c;科技发展飞速&#xff0c;为我们打开了无数新的视角和可能性。其中&#xff0c;虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;技术的崭新应用&#xff0c;为我们提供了一种全新的、近乎身临其境的体验历史的方式。本文将重点…

全网最全Kettle教程-Kettle概述

文章目录 第一章 Kettle概述1.1 Kettle发展历程1.2 Kettle简介1.3 Kettle相关俗语1.4 Kettle设计与组成1.5 Kettle功能模块1.6 Kettle的执行Transformation&#xff08;转换&#xff09;1.7 Kettle商业和社区版区别1.8 数据集成与ETL1.9 ETL工具比较 第一章 Kettle概述 1.1 Ke…