同步 -- 信号量

2023-09-19 09:49:57

 本篇文章基于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); //唤醒任务
}
更多推荐

代码配置仓库GitLab安装部署

Github是目前世界上代码行数最多的在线软件版本配置库平台,而Gitlab是Github对应的开源版本,本文主要描述Gitlab的安装部署。https://about.gitlab.com/https://gitlab.cn/install/如上所示,从官方网站中下载不同操作系统的版本,本文主要描述Centos的安装

UML类图

优质博客:IT-BLOG-CNUML(UnidiedModelingLanguage)统一建模语言:用来设计软件的可视化建模语言,能够表达软件设计中的动态与静态信息。UML定义了用例图、类图、对象图、状态图、活动图、时序图、协作图、构件图、部署图等9种图。IDEA展示类图及类图关系【1】选中.java或者编辑的.jav

部署Kafka

kafka:kafka_2.13-3.5.1NOTE:YourlocalenvironmentmusthaveJava8+installed.ApacheKafkacanbestartedusingZooKeeperorKRaft.Togetstartedwitheitherconfigurationfollowone

MySQL 篇

目录1、数据库三范式2、数据库事务的特性3、MySQL数据库引擎4、说说InnoDB与MyISAM的区别5、索引是什么?6、索引数据结构7、MySQL索引类型有哪些?8、索引有什么优缺点?9、索引设计原则9、使用索引应该注意些什么?10、什么是视图?11、什么是内联接、左外联接、右外联接?12、说一说drop、dele

网络安全(黑客技术)自学规划

一、什么是网络安全网络安全可以基于攻击和防御视角来分类,我们经常听到的“红队”、“渗透测试”等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。无论网络、Web、移动、桌面、云等哪个领域,都有攻与防两面性,例如Web安全技术,既有Web渗透,也有Web防御技术(WAF)。作为一个合格的网络安全工程

Caton Media Xstream: 重新定义实时内容交付服务

//编者按:随着公共互联网愈加复杂,besteffort的基本原型已无法满足越来越多的有QoS保障需求的实时内容交付服务。而专线、卫星等传统解决方案存在部署成本高、周期长等问题,无法快速响应各类需求。LiveVideoStackCon邀请到了科腾科技的魏凌,为我们介绍CatonMediaXstream平台的解决方案。文

selenium环境+元素定位大法

selenium与webdriverSelenium是一个用于Web测试的工具,测试运行在浏览器中,就像真正的用户在手工操作一样。支持所有主流浏览器WebDriver就是对浏览器提供的原生API进行封装,使其成为一套更加面向对象的SeleniumWebDriverAPI。使用这套API可以操控浏览器的开启、关闭,打开网

Springboot登录验证的统一拦截处理

在进行Springboot项目开发的时候如何把每次请求都要验证的用户进行提取拦截统一处理背景如果不进行统一的拦截处理,其实这是一个非常痛苦的一件事情,因为每次用户请求你都要去进行用户的信息(用户信息存储在session中)的验证,代码重复,所以在本篇提供一个解决方案:定义一个拦截器,把请求都进行统一的处理,如果Sess

基于FPGA的图像白平衡算法实现,包括tb测试文件和MATLAB辅助验证

目录1.算法运行效果图预览2.算法运行软件版本3.部分核心程序4.算法理论概述5.算法完整程序工程1.算法运行效果图预览2.算法运行软件版本vivado2019.2matlab2022a3.部分核心程序`timescale1ns/1ps////Company://Engineer:////CreateDate:2023

全志H3 Linux编译尝试

全志H3Linux编译尝试主要参考:https://blog.csdn.net/qq_40731414/article/details/118684473部分内容介绍来自GPT,但是代码部分都会进行测试一、简介Linux编译的作用:生成可执行的内核映像:编译Linux内核的主要目的是从源代码生成一个可执行的内核映像(例

JDBC基本概念

什么是JDBCJDBC概念JDBC(JavaDataBaseConnectivity)是一套统一的基于Java语言的关系数据库编程接口规范。该规范允许将SQL语句作为参数通过JDBC接口发送给远端数据库,远端数据库接收到SQL语句后进行语法分析、验证,然后执行、响应。JDBC驱动在遵循统一的JDBC接口规范基础上,不同

热文推荐