Day23 semaphore, mutex

前言

昨天花了很大的篇幅在学习spinlock ,可惜最重要的一部分 queued spinlock,还没有机会完全参透,希望之後有机会把他弄懂,再回头把昨天的笔记补完!! 今天也是要来学期除了 spinlock 、 atomic 以外,其他的同步锁。

semaphore

semaphore 是作业系统中最常用的同步锁之一。 spinlock 允许行程持续等待获取一个锁,相对的 semaphore 则是让行程进入睡眠状态,简单来说 semaphore就是计数器,利用 up 与 down 计算拥有锁的行程有几个。
semaphore中最常见的例子就是消费者与生产者问题,生产者生产商品,消费者购买商品,生产者生产商品的行为就像是 semaphore 增加,消费者购买商品就像是 semaphore减少。
以下是semaphore的资料结构定义:

// <include/linux/semaphore.h>
struct semaphore {
	raw_spinlock_t		lock;
	unsigned int		count;
	struct list_head	wait_list;
};

lock :是spinlock变量,保护 count wait_list
count : 表示可以进入C.S的个数。
wait_list:管理在该 semaphore 上睡眠的行程,没有获得锁的行程会睡眠在这个list上。
下面列出三个最常见的 semaphore 操作函数

static inline void sema_init(struct semaphore *sem, int val)
extern void up(struct semaphore *sem);
extern void down(struct semaphore *sem);

semaphore的特点就是他可以同时允许任意数量的锁持有者,只要在semaphore的初始化时,将count 宣告成需要的数字即可,semaphore用於一些情况复杂,加锁时间比较长的应用场景,像是kernel 与 user space的复杂交互行为。

about extern

变数使用前要先宣告(declaration),C 的 extern 关键字,用来表示此变数已经在别处定义(definition),告知程序到别的地方找寻此变数的定义(可能在同一个档案或其他档案)。

mutex

在 Linux中,有种类似 semaphore的机制叫做 mutex, semaphore 在同步处理的环境中对多个处理器访问某个分享资源进行保护的机制,mutex则适用於互斥操作。
但若是将 semaphore的 count 设定为1,并且利用 down()up() 仍然可以完成类似互斥锁的结果,这样为什麽要但读实现互斥机制呢?
因为互斥锁的实现比较简单与轻便,在锁竞争激烈的测试场景中,互斥锁比 semaphore的执行速度还要快,可扩展性更好,互斥锁的数据结构也比semaphore还要小,所以才会单独实现。
下面是 mutex 的数据结构定义

// <include/linux/mutex.h>
struct mutex {
	atomic_long_t		owner;
	spinlock_t		wait_lock;
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
	struct optimistic_spin_queue osq; /* Spinner MCS lock */
#endif
	struct list_head	wait_list;
};

count : 1代表没有行程持有锁,0代表有持有,负数代表有被持有且有行程在等待队列中。
wait_lock :保护 wait_list
wait_list :管理所有在mutex上的所有行程。
ower :指向锁拥有者的 task_struct
osq :用於实现MCS锁的机制。

#define DEFINE_MUTEX(mutexname) \
	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
    
extern void mutex_lock(struct mutex *lock);
extern void mutex_unlock(struct mutex *lock);

The Linux document 中列出了使用mutex需要注意的条件

The mutex subsystem checks and enforces the following rules:

  • Only one task can hold the mutex at a time.
  • Only the owner can unlock the mutex.
  • Multiple unlocks are not permitted.
  • Recursive locking/unlocking is not permitted.
  • A mutex must only be initialized via the API (see below).
  • A task may not exit with a mutex held.
  • Memory areas where held locks reside must not be freed.
  • Held mutexes must not be reinitialized.
  • Mutexes may not be used in hardware or software interrupt contexts such as tasklets and timers.

<<:  Day23 DB-NodeJS中的MySQL

>>:  专注,就是你要懂得说不。

.Net Core Web Api_笔记24_api结合EFCore资料库操作part2_产品分类资料新增_资料查询呈现(带入非同步API修饰)

接续上一篇 在Startup.cs中启用静态资源 於专案新增目录命名为wwwroot(会自动变成地球...

Debian10安装iRedMail v1.2.1详细教程

iRedMail简介 iRedMail是基于开源的postfix、dovecot、openldap...

Day 29 | Keep Going 13 - Github page

嘿不知不觉的就来到倒数第二篇了呢!网页也写完了呢!是不是要发布了哇! 今天就来说说 Github p...

Day-9 Excel筛选大秘辛

今日练习档 ԅ( ¯་། ¯ԅ) 经过昨天的排序介绍後,今天就来到了排序後通常会进行的「筛选」,接着...

[Day1] JavaScript Drum Kit

关於 Javascript 30天 课程介绍 Javascript30,是由加拿大全端工程师 Wes...