iT邦幫忙

2021 iThome 鐵人賽

DAY 24
0
自我挑戰組

當你凝視linux, linux也在凝視你系列 第 24

Day24 read-write lock

前言

昨天講完了 mutex, semaphore ,今天仍要繼續朝著各種不同的 lock前進,昨天講的semaphore,有個明顯的缺點,沒辦法知道在 C.S裡的行程究竟是讀還是寫。 rwlock 可以有效的提高並行性,rwlock可以允許多個執行緒存取c.s 但是寫入就只能有一個行程。

rwlock

rwlock 具有以下的特性

  • 允許多個讀取行程,但同時刻不能有寫入行程
  • 同一個時刻只能有一個寫入行程
  • 寫入行程與讀取行程不能同時進入C.S

rwlock 有兩種,分別是 spinlock型與 semaphore型。

以下是 spinlock型的定義

// <include/linux/rwlock_types.h >
typedef struct{
    arch_rwlock_t raw_lock;
}rwlock_t

// <arch/arm/include/asm/spinlock_types.h>
typedef sturct{
    u32 lock;
}arch_rwlock_t;

以下是常見的函數:

  • rwlock_init() : 初始化rwlock。
  • write_lock() : 申請寫入鎖。
  • write_unlock() : 釋放寫入鎖。
  • read_lock() : 申請讀取鎖。
  • read_unlock() :釋放讀取鎖。
  • read_lock_irq() : 關閉中斷並且申請讀取鎖。
  • write_lock_irq() :關閉中斷並且申請寫入鎖。
  • write_unlock_irq() :打開中斷並且釋放寫者鎖。

read-write semaphore

//<include/linux/rwsem.h>

struct rw_semaphore {
	atomic_long_t count;
	struct list_head wait_list;
	raw_spinlock_t wait_lock;
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
	struct optimistic_spin_queue osq; /* spinner MCS lock */
	/*
	 * Write owner. Used as a speculative check to see
	 * if the owner is running on the cpu.
	 */
	struct task_struct *owner;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	struct lockdep_map	dep_map;
#endif
};

wait_lock : 是一個 spinlock變量,用以保護 rw_semaphore 資料結構中的 count 成員。
count :用來保護 read-write semaphore 的計數。
wait_list :管理所有在 semaphore上的睡眠行程,沒有獲取鎖的行程會睡眠在這個鏈表。
osq : 表示MCS鎖。
owner : 寫者獲取鎖的時候, owner 指向鎖持有者的 task_struct 資料結構。

其中將 count 拿出來看

/*
 * the semaphore definition
 */
#ifdef CONFIG_64BIT
# define RWSEM_ACTIVE_MASK		0xffffffffL
#else
# define RWSEM_ACTIVE_MASK		0x0000ffffL
#endif

#define RWSEM_UNLOCKED_VALUE		0x00000000L
#define RWSEM_ACTIVE_BIAS		0x00000001L
#define RWSEM_WAITING_BIAS		(-RWSEM_ACTIVE_MASK-1)
#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)

count 應該要看成兩段,分別為低位的 [15:0]位元,代表了正在持有鎖的讀取者或是寫入者的個數; [31:16]為元,通常是一個負數,代表有一個正在持有鎖或是處於等待狀態的寫入者,以及睡眠等待隊列有人在等待。
例子如下

  • RWSEM_ACTIVE_READ_BIAS = 0x00000001 ,即二元[0,1]表示只有一個讀取者。
  • RWSEM_ACTIVE_WRITE_BIAS = 0xffff0001, 二元數[-1,1],表示當前只有一個活躍的寫入者。
  • RWSEM_WAITING_BIAS = 0xffff0000 即[-1, 0]代表睡眠等待隊列中有人在睡眠等待 。

rw-lock 在kernel中應用廣泛,特別是在內存管理經常會使用到除了前面的 mm->mmap_sem 的rw semaphore以外, RMAP系統中的 anon_vma->rwsem 、 address space 資料結構中的 i_mmap_rwsem 等。

最後再整理幾個rw lock的重要特性:

  • down_read() : 如果行程有了read lock,允許行程繼續申請更多的 read lock,但是申請 write lock則需要睡眠等待
  • down_write() :如果一個行程有了 write lock ,另一個行程想申請 write lock 時,需要用 spinlock等待,申請 read lock 則需要睡眠等待。
  • up_write() / up_read() :若等待列上第一個成員是寫入者,則只喚醒他; 若為讀取行程,則喚醒等待列最前面幾個連續的讀取者。

上一篇
Day23 semaphore, mutex
下一篇
Day25 RCU 同步機制
系列文
當你凝視linux, linux也在凝視你30

尚未有邦友留言

立即登入留言