首页 > 其他分享 >20 同步与互斥(六)semaphore

20 同步与互斥(六)semaphore

时间:2023-04-29 20:33:05浏览次数:38  
标签:__ 20 struct list 信号量 互斥 semaphore sem

1 简介

semaphore信号量;需要注意的是信号量不是信号。

信号量是一种同步、互斥机制

2 semaphore的结构和API

2.1 semaphore结构

struct semaphore sem;
struct semaphore {
	raw_spinlock_t		lock;				// semaphore借助与spinlock实现
	unsigned int		count;				// 允许多少人使用这个semaphore
	struct list_head	wait_list;			// 等待信号量的线程
};

2.2 semaphore API

  • DEFINE_SEMAPHORE(name)

    定义一个struct semaphore name结构体count值为1

  • void sema_init(struct semaphore *sem, init val)

    初始化semaphore。需要注意的是wait_list在这里被初始化了,休眠时将内核申请到的wait线程放入此

    #define __SEMAPHORE_INITIALIZER(name, n)				\
    {									\
    	.lock		= __RAW_SPIN_LOCK_UNLOCKED((name).lock),	\
    	.count		= n,						\
    	.wait_list	= LIST_HEAD_INIT((name).wait_list),		\
    }
     
    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);
    }
    
  • void down(struct semaphore *sem)

    获得信号量,如果无法获得就会休眠。休眠过程中无法被唤醒

  • int down_interruptible(struct semaphore *sem)

    获得信号量,如果无法获得就会休眠。休眠过程中会被信号唤醒

    return

    • 0:获得信号量
    • -EINTR:被信号打断
  • int down_killable(struct semaphore)

    获得信号量,如果无法获得就会休眠。休眠过程中除了信号量就只有fatal signal信号唤醒能唤醒

    return

    • 0:获得信号量
    • -EINTR:被信号打断
  • int down_trylock(struct semaphore *sem)

    尝试获取信号量,不会休眠

    return

    • 0:获得了信号量
    • 1:没有获得信号量
  • int down_timeout(struct semaphore *sem, long jiffies)

    获取信号量,如果不成功则休眠一段时间

    return

    • 0:获得信号量
    • -EINTR:规定时间内未获得信号量
  • void up(struct semaphore *sem)

    释放信号量,唤醒其他等待信号量的进程

3 semaphore 实现机制

3.1 信号量的获取

down -> __down -> __down_common

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

	raw_spin_lock_irqsave(&sem->lock, flags);			// 上锁,互斥的访问count
	if (likely(sem->count > 0))
		sem->count--;									// 如果count大于0,就减减,成功获取信号量。
	else
		__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 task_struct *task = current;
	struct semaphore_waiter waiter;

	list_add_tail(&waiter.list, &sem->wait_list);			// 等待进程放入信号量的wait_list
	waiter.task = task;
	waiter.up = false;

	for (;;) {
		if (signal_pending_state(state, task))
			goto interrupted;
		if (unlikely(timeout <= 0))
			goto timed_out;
		__set_task_state(task, state);						// 修改进程状态为非running
		raw_spin_unlock_irq(&sem->lock);					// 解锁
		timeout = schedule_timeout(timeout);				// 让出CPU, 开始调度
		raw_spin_lock_irq(&sem->lock);						// 被唤醒后,上锁。解锁在上上级函数中实现
		if (waiter.up)										// 如果获得信号量,则返回
			return 0;
	}

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

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

3.2 3.1 信号量的释放

up -> __up

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

	raw_spin_lock_irqsave(&sem->lock, flags);
	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->list中删除
	waiter->up = true;													// 设置标记,表示此等待函数获得信号量
	wake_up_process(waiter->task);										// 唤醒得到的信号量进程
}

标签:__,20,struct,list,信号量,互斥,semaphore,sem
From: https://www.cnblogs.com/burnk/p/17364451.html

相关文章

  • 2023-04-29 动态规划介绍
    2023-04-29动态规划介绍动态规划是运筹学课程的一部分多阶段决策问题有一类活动的过程,可以分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果当然,每个阶段的决策的选取不是任意确定的,它依赖于当前的状态,又会影响以后的发展如下图,①......
  • 2023.4.29
    1//课本习题8-52#include<iostream>3#include<string>4usingnamespacestd;5classMammal6{7public:8virtualvoidspeak()9{10cout<<"动物正在说话"<<endl;11}12};13classDog:publicMam......
  • cf-typedb2023-C
    题目链接:https://codeforces.com/problemset/problem/1787/C我是sb,这种dp都没想到。。。思路:首先得发现一个性质(贪心),每个数拆成的两个数一定是一个最大的(尽可能),另一个最小(尽可能)。这点不难证明,随便写写式子可得证。由于每个数只会影响相邻的两个数,所以我们可以dp算答案。......
  • 19 同步与互斥(五)自旋锁
    1简介自旋锁:通俗的说就是自己在原地打转,一直等待资源可用。不会休眠对临界资源的访问时,因为自旋锁的存在,某段临界资源被占用后。其他事件将无法访问,即进行所谓的自旋,“原地打转”注意:在自旋锁的临界区不能使用可能引起进程调度的函数(因为抢占已经被禁止了)。示例: copy_to_......
  • HZNUCTF2023
    前言还是要向大师傅们orz,本人太菜了。希望大师傅们可以来指点本菜鸡,让本坤能快点理解wp,QAQ。easy_rw查保护,和禁用系统调用静态分析程序漏洞。程序功能很简单,就是一个栈溢出。但是仅溢出0x28字节,本人思路是先泄露libc,再打一个栈迁移。expfrompwncyimport*context(arch......
  • 2023.4.29——软件工程日报
    所花时间(包括上课):0h代码量(行):0行博客量(篇):1篇今天,数学建模比赛中。。。我了解到的知识点:数学建模的相关知识 ......
  • 【题解】P3920 [WC2014]紫荆花之恋
    思路点分树+根号重构+*高速平衡树。点分树的两种常见用法无非是直接做和路径有关的暴力还有处理这种有关单点和整树的问题,后者的另一个经典题目是P3241[HNOI2015]开店。回到这个题目,处理路径考虑先上点分治,暂时不考虑强制在线的限制。因为每次加上一个新点,所以可以考......
  • [CEOI2021] Newspapers
    模拟赛没有判\(n=1\),喜提\(0\)分。感谢每个subtask都放\(n=1\)的善良出题人。看到题感觉A的操作好像比较弱小,唯一的用处似乎只能用来排除B在哪些位置,那这样就有一个暴力了,直接记录当前还有哪些点上可能有B,然后直接跑bfs,就可以通过第一档分了。看到第二档分似乎比较......
  • SequoiaDB分布式数据库2023.4月刊
    本月看点速览赋能产业升级,荣获新睿之星聚焦金融,进一步探索非结构化数据价值释放再获肯定,入选2023年中国最佳信创厂商入围名单青杉计划2023已开启,一起攀登更高的“杉” 赋能产业升级,荣获新睿之星4月18日,2023年第九届广州国际投资年会在广州白云国际会议中心成功举办。会中......
  • P6818 [PA2013]Działka 题解
    P6818[PA2013]Działka前言我太菜了。。。。对着jiangly大佬的题解研究了一下午研究了一下午才搞出来(泪目。作为一个蒟蒻,我就详细的讲一下我对与本题的理解。题意本题的的题意描述的还是比较明了。在二维坐标系中,输入\(n\)个点\(m\)次询问,每次询问,给出一个矩阵,......