日期:2014-05-16  浏览次数:20585 次

linux内核--内核同步介绍

希望通过这一章可以知道什么是同步,不管从哪个层次哪个角度。

    在单一处理器的时候,只有在中断发生的时候,或在内核代码明确地请求重新调度、执行另一个任务的时候,数据才可能被并发访问。支持多处理器意味着内核代码可以同时运行在两个或更多的处理器上。因此,如果不加保护,运行在两个不同处理器上的内核代码完全可能在同一时刻里并发访问数据。

一、临界区和竞争条件

    所谓临界区就是访问和操作共享数据的代码段。多个执行线程并发访问同一个资源通常是不安全的,为了避免在临界区中并发访问,编程者必须保证这些代码原子地执行,也就是说操作在执行结束前不可被打断,就如同整个临界区是一个不可分割的指令一样。如果两个执行线程有肯那个处于同一个临界区中同时执行,那么着就是程序包含的一个bug。如果这种情况确实发生了,我们就称它是竞争条件。避免并发和防止竞争条件称为同步。

   这种临界区的假设非常常见,比如ATM存款等等,同时读取同一个数字。

二、加锁

    假设需要处理一个队列上的所有请求,我们假设该队列是通过链表得以实现,链表中的每个节点就代表一个请求。两个函数可以操作此队列:一个函数将新请求添加到队列末尾,一个函数从队列头删除请求,然后处理它。内核各个部分都会调用这两个函数。如果一个线程试图读取队列,而这时正好另一个线程正在处理该队列,那么读取线程就会发现队列此刻正处于不一致状态。很明显,如果允许并发访问队列,就会产生危害。当共享资源是一个复杂的数据结构时,竞争条件往往会使该数据结构遭到破坏。

    锁机制提供了一种方法来解决这个问题:它就如同一把门锁,门后的房间可想象成一个临界区。在一个指定的时间内,房间里只能有一个执行线程存在,当一个线程进入房间后,它就锁住身后的房门;当结束对共享数据的访问时,就走出房间,打开门锁。如果另一个线程在房门上锁时来了,那么就必须等待房间内的线程出来并打开门锁后,才能进入房间。

    用户空间之所以需要同步,是因为用户进程会被调度程序抢占和重新调度。由于用户进程可能在任何时刻被抢占,而调度程序完全可能选择另一个优先级的进程到处理器上执行,所以就会使得一个程序正处于临界区时,被非自愿地抢占了。如果新调度的进程随后也进入同一个临界区,前后两个进程相互之间就会产生竞争。

    内核中有类似可能造成并发执行的原因:

  • 中断,中断几乎可以在任何时刻异步发生,也就可能随时打断当前正在执行的代码
  • 软中断和tasklet,内核能在任何时刻唤醒或调度软中断和tasklet,打断当前正在执行的代码
  • 内核抢占,因为内核具有抢占性,所以内核中的任务可能会被另一个任务抢占
  • 睡眠及用户空间的同步,在内核执行的进程可能会睡眠,这就会唤醒调度程序,从而导致调度一个新的用户进程执行
  • 对称多处理,两个或多个处理器可以同时执行代码

    但是需要知道的是,加锁的对象是数据而不是代码。

三、死锁

    死锁的产生需要一个条件:要有一个或多个执行线程和一个或多个资源,每个线程都在等待其中的一个资源,但所有的资源都已经被占用了。所有线程都在相互等待,但他们永远