Concurrency and Race Conditions [LDD3 05]

Table of Contents

Concurrency and Its Management

Semaphores and Mutexes

The Linux Semaphore Implementation

Reader/Writer Semaphores

Completions

Spinlock

Introduction to the Spinlock API

Spinlocks and Atomic Context

The Spinlock Functions

Reader/Writer Spinlocks

Locking Traps

Ambiguous Rules

Lock Ordering Rules

Fine- Versus Coarse-Grained Locking

Alternatives to Locking

Lock-Free Algorithms

Atomic Variables

Bit Operations

seqlock

Read-Copy-Update


在最开始,kernel是不支持并发的,同一时刻只能有一个正在运行的code。后来随着硬件的升级,以及对performance的追求,kernel需要充分利用硬件的特性,才引入了并发。因为同一时刻可能有多个进程在执行,因此device driver需要考虑并发冲突的问题。

Concurrency and Its Management


并发和竞争条件,这个是计算机操作系统里经典话题。并发是一个很复杂的场景,复杂到没有人能预测当前的code会是怎么样的环境下执行,看似简答的device driver code,也许因为时间片用完,CPU被切走了;可能中断发生,CPU处理中断去了;可能多个进程同时执行,多CPU同时在执行同一段code,访问同一个全局资源;另外,还要考虑资源是否可用,是否会休眠,以及device的hotplug,而且,kernel中还提供了delay的机制,比如workqueue,timer,tasklet等,可以让code在将来的某个时刻还行,这些都会引入并发,有并发就可能存在问题,这在coding的时候其实是很难考虑全面的。

kernel提供了很多用于防止竞争条件产生的方式,主要是加锁,比如mutex/spinlock等。竞争条件的产生,最直接的原因就是多个进程/线程访问了共享的资源,如果能够少共享资源,就能减少竞争条件的发生,因此driver里要尽量少的使用全局变量,这是第一个原则。但是在实际的device driver中,全局共享变量不要太多,而且device resource本身肯定是share的。在kernel中,共享很难避免,既然不能不用共享资源,那就对共享资源进行加锁以保证互斥访问,这是第二个原则。能记住这两个原则,就能解决竞争条件的问题:尽可能少的使用全局共享变量,如果必须共享,就加锁保护。

如果要加锁,那么 kernel中的共享资源或者共享变量必须能够一直存在并正常工作,直到没有任何的reference。因为是共享的,所以不止一个人在使用,如果在有人使用的情况下共享资源或者变量除了问题,那么所有使用它的人都会碰到问题。从这一点又可以引申出来几个注意事项:

1, device driver必须能够正常处理所有的request,直到没有被open的device。

2,在kernel driver真正ready之前,不要暴露接口给kernel;

3,所有的object/resource要能够track,比如通过reference counter。

下面,就是操作系统里保证资源互斥访问的几种方式。

Semaphores and Mutexes


在保护资源之前,要先确定critical section,也就是一次只能运行一个线程执行的代码段,只有确定了critical section,才可以使用系统的保护机制对资源进

你可能感兴趣的:(Linux,LDD3,驱动,多线程)