Linux Kernel Development 3rd Edition 读书笔记(5)

第九章 An Introduction to Kernel Synchronization
1. pseudo-concurrency: 访问不同时发生,但是互相发生交错.
2. 内核并发性的原因有:Interrupts, Softirqs and tasklets, Kernel preemption, Sleeping and synchronization with user-space,Symmetrical multiprocessing.
3. 使用频繁的lock会降低系统的性能.

这章讲的是内核同步的基本概念,很多都是操作系统的共有概念,如临界区,死锁等.故不做详细笔记.

第十章 Kernel Synchronization Methods
1. 原子访问的整形数据使用特殊的类型atomic_t(<linux/types.h>)
typedef struct {
volatile int counter;
} atomic_t;
使用方法:

atomic_t v;                   /* define v */ 
atomic_t u = ATOMIC_INIT(0);  /* define u and initialize it to zero */
Operations are all simple:
atomic_set(&v, 4);     /* v = 4 (atomically) */ 
atomic_add(2, &v);     /* v = v + 2 = 6 (atomically) */ 
atomic_inc(&v);        /* v = v + 1 = 7 (atomically) */
If you ever need to convert an atomic_t  to an int, use atomic_read():
printk(“%d\n”, atomic_read(&v));   /* will print “7” */

atomic_t相关函数实现在<asm/atomic.h>.
所有函数如下图:
Linux Kernel Development 3rd Edition 读书笔记(5)_第1张图片
2.Atomicity Versus Ordering
Atomicity:读一个字的完整状态.可能在写之前,也可能在写之后,但绝不会写的过程中.
Ordering:要求顺序读,如要求在写之前读,这是Ordering而不是Atomicity.本节讨论的都是Atomicity操作,而Ordering通过barrier 操作.

3.原子位操作

和整形数操作类似, 定义在<asm/bitops.h>.
非原子访问的位操作函数有两个下划线的前缀,如__test_bit().


以下两个函数用来返回一个字数据第一个被设置或清楚的位编号.
int find_first_bit(unsigned long *addr, unsigned int size)
int find_first_zero_bit(unsigned long *addr, unsigned int size)

4. Spin lock
Spin lock一次最多被一个线程执行时拥有.spin lock被占有时,线程会一直等待,因此持有spin lock不应太长时间.
 <asm/spinlock.h>: 架构相关代码.
 <linux/spinlock.h>: 实际使用的接口.
基本使用方法:
DEFINE_SPINLOCK(mr_lock);
spin_lock(&mr_lock);
/* critical region ... */
spin_unlock(&mr_lock);
中断服务程序中:
DEFINE_SPINLOCK(mr_lock);
unsigned long flags;
spin_lock_irqsave(&mr_lock, flags);
/* critical region ... */
spin_unlock_irqrestore(&mr_lock, flags);

Lock data, not code.

中断初始化时已使能(不推荐):
spin_lock_irq(&mr_lock);
/* critical section ... */
spin_unlock_irq(&mr_lock);


Linux Kernel Development 3rd Edition 读书笔记(5)_第2张图片

5. Reader Writer Spin Lock
一个或多个reader可同时拥有reader lock, 但writer lock同时只能有一个writer拥有,且没有并行的reader.
用法如下:
Usage is similar to spin locks.The reader-writer spin lock is initialized via
DEFINE_RWLOCK(mr_rwlock);
Then, in the reader code path:
read_lock(&mr_rwlock);
/* critical section (read only) ... */
read_unlock(&mr_rwlock);
Finally, in the writer code path:
write_lock(&mr_rwlock);
/* critical section (read and write) ... */
write_unlock(&mr_lock);



6. Semaphore
需要sleep或者长时间等待lock应使用信号量.
静态声明初始化信号量:
struct semaphore name;
sema_init(&name, count);
或者使用宏:
static DECLARE_MUTEX(name);
动态声明初始化信号量:
sema_init(sem, count);
或者使用宏:
init_MUTEX(sem);
Linux Kernel Development 3rd Edition 读书笔记(5)_第3张图片

7. Reader-Writer Semaphores
使用struct rw_semaphore,在 <linux/rwsem.h>声明.
静态创建: static DECLARE_RWSEM(name);
动态创建: init_rwsem(struct rw_semaphore *sem);

reader-writer semaphores是互斥的(指writer是互斥,reader可以并发read).
Example:

static DECLARE_RWSEM(mr_rwsem);
/* attempt to acquire the semaphore for reading ... */ 
down_read(&mr_rwsem);
/* critical region (read only) ... */
/* release the semaphore */ 
up_read(&mr_rwsem);
/* ... */
/* attempt to acquire the semaphore for writing ... */ 
down_write(&mr_rwsem);
/* critical region (read and write) ... */
/* release the semaphore */ 
up_write(&mr_sem);

8. Mutex静态声明: DEFINE_MUTEX(name);动态声明: mutex_init(&mutex);使用:mutex_lock(&mutex); /* critical region ... */ mutex_unlock(&mutex);

Linux Kernel Development 3rd Edition 读书笔记(5)_第4张图片
Spin Locks Versus Sempaphores
Linux Kernel Development 3rd Edition 读书笔记(5)_第5张图片

9. Completion VariablesCompletion Variables和semaphore类似,但提供更简单的方法来在2个任务间进行同步.如vfork()就是使用这样的机制,当子进程退出,便使用Completion Variables来通知父进程. struct completion, 定义在 <linux/completion.h>.静态声明: DECLARE_COMPLETION(mr_comp);动态创建: init_completion().Linux Kernel Development 3rd Edition 读书笔记(5)_第6张图片10. BKL(the Big Kernel Lock)BKL是从全局的spin lock,用来简化从Linux SMP实现到精细locking的传输. 不鼓励使用,在新版本kernel中,越来越少使用. 定义在<linux/smp_lock.h>.11. Sequential Locks2.6内核新的lock.提供了读写共享数据的简单机制.持有一个sequence counter.定义seq lock: seqlock_t mr_seq_lock = DEFINE_SEQLOCK(mr_seq_lock);写:

write_seqlock(&mr_seq_lock);
/* write lock is obtained... */
write_sequnlock(&mr_seq_lock);
读:
unsigned long seq;
do {
seq = read_seqbegin(&mr_seq_lock);
/* read data here ... */
} while (read_seqretry(&mr_seq_lock, seq));


当以下情况时推荐使用seq lock:a lot of readers/few writersfavor writers over readers and never allow readers to starve writersdata is simple10. Preemption DisablingLinux Kernel Development 3rd Edition 读书笔记(5)_第7张图片11. Ordering and Barriers告之编译器在某点不跳转指令执行顺序来进行优化叫Barriers.Intel x86 processors do not ever reorder writes. That is, they do not do out-of-order stores. But other processors do.rmb()来实现读内存的Barriers来避免reordering. wmb()来实现写的Barriers.  mb()针对读和写.read_barrier_depends()针对有关联的数据读, 比rmb()速度快,开销小.barrier()用来防止编译器进行优化产生reordering, compiler barrier比memory barrier轻量级.Linux Kernel Development 3rd Edition 读书笔记(5)_第8张图片Linux Kernel Development 3rd Edition 读书笔记(5)_第9张图片


   

你可能感兴趣的:(Linux Kernel Development 3rd Edition 读书笔记(5))