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

来源:互联网 发布:java按键子弹不走 编辑:程序博客网 时间:2024/05/16 13:51

第九章 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>.
所有函数如下图:

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);




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);


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);


Spin Locks Versus Sempaphores

9. Completion VariablesCompletion Variables和semaphore类似,但提供更简单的方法来在2个任务间进行同步.如vfork()就是使用这样的机制,当子进程退出,便使用Completion Variables来通知父进程. struct completion, 定义在 <linux/completion.h>.静态声明: DECLARE_COMPLETION(mr_comp);动态创建: init_completion().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 Disabling11. 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轻量级.

	
				
		
原创粉丝点击