昨天花了很大的篇幅在学习spinlock ,可惜最重要的一部分 queued spinlock,还没有机会完全参透,希望之後有机会把他弄懂,再回头把昨天的笔记补完!! 今天也是要来学期除了 spinlock 、 atomic 以外,其他的同步锁。
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的复杂交互行为。
变数使用前要先宣告(declaration),C 的 extern 关键字,用来表示此变数已经在别处定义(definition),告知程序到别的地方找寻此变数的定义(可能在同一个档案或其他档案)。
在 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.
接续上一篇 在Startup.cs中启用静态资源 於专案新增目录命名为wwwroot(会自动变成地球...
iRedMail简介 iRedMail是基于开源的postfix、dovecot、openldap...
嘿不知不觉的就来到倒数第二篇了呢!网页也写完了呢!是不是要发布了哇! 今天就来说说 Github p...
今日练习档 ԅ( ¯་། ¯ԅ) 经过昨天的排序介绍後,今天就来到了排序後通常会进行的「筛选」,接着...
关於 Javascript 30天 课程介绍 Javascript30,是由加拿大全端工程师 Wes...