zoukankan      html  css  js  c++  java
  • 读书笔记Linux内核设计与实现part 2

    Chapter 9~10 内核同步》

    临界区(CS):访问共享资源的代码段。

    造成并发的原因:

    1. 中断
    2. 软中断和tasklet
    3. 内核抢占
    4. 睡眠及用户空间的同步
    5. 对称多处理器

     

    锁的使用本身并不是难点,真正的挑战在于辨认出需要共享的数据和相应的临界区。

    在最开始设计代码的时候就要想到要使用锁,而不是在完成代码后再去加锁。

    interrupt-safe / SMP-safe / preempt-safe

    预防死锁的一个比较方便的方法(不能彻底解决):按顺序枷锁。

     

    死锁的四个条件:

    互斥(mutual exclusion),

    请求与保持(hold and wait),

    非剥夺(non-preempt),

    循环等待(circular wait)。

     

    Linux锁粒度越来越细,可扩展性也很好。

     

    原子变量,原子位操作。

     

    自旋锁:

    自旋锁可以使用在中断处理函数中(这里不能使用信号量,因为信号量会导致睡眠)。

    申请自旋锁前,先关本地中断(有接口实现关中断和申请自旋锁)。

    针对数据结构加锁。

    spin_try_lock()试图去获得某个自旋锁,如果该锁已被争用,立刻返回非零值,不会等待锁被释放。

    读写自旋锁:共享读,互斥写。

       错误使用读写自旋锁,导致死锁:

            read_lock(&mr_rwlock);

            write_lock(&mr_rwlock);//等待所有读者退出(包括自己这个读者)

     

    信号量:

    一种睡眠锁。1986年由Dijkstra提出,接口P(),V()(来自荷兰语Proberen和Vershogen,分别是探查和增加的意思,Linux中称为down(),up())。

    读写信号量。

     

    互斥体:

    可以睡眠的强制互斥锁。

     

    完成变量:

    一个任务完成后需要通知另一个任务,使用完成变量(completion variable)。

    三个API:

    init_completion(struct completion *);
    
    wait_for_completion(struct completion *);
    
    complete(struct completion *);

     

    BKL大内核锁:
       Linux支持单CPU到支持SMP过渡期的锁。

     

    顺序锁:

       u64 get_jiffies_64(){
           unsigned long seq;
           u64 ret;
           do{
              seq = read_seqbegin(&xtime_lock);
              ret = jiffies64;
           }while(read_seqretry(&xtime_lock,seq));
           return ret;
      }
    //写jiffies write_seqlock(&xtime_lock); jiffies_64 += 1; write_sequnlock(&
    xtime_lock);

     

    顺序和屏障:

    rmb()保证其后的读内存操作在其前的读内存操作之后执行(现代处理器中为优化流水线可能会有乱序执行的情况)。

    wmb()与之类似,mb()是rmb(),wmb()两种屏障。

    例如:a,b原来初始值为1,2;

    线程1                     线程2                    
    ④a=3; ---
    mb(); ---
    ①  b=4; ②  c=b;
    --- rmb();
    --- ③  d=a;

    如果没有mb(),rmb(),则可能发生c=4,d=1的情况(执行序列如图中序号,我们并不希望是这样的)。加上mb(),rmb()之后就避免了这种情况。

     

    barrier()阻止编译器跨屏障对载入或存储操作优化。

     

    Chapter 11 定时器和时间管理》

     

    #define time_before(unkown,know)  ((long)(known)-(long)(unknow)<0)

    x86 PIT(可编程中断时钟)

     

    定时器:由这个结构体实现。

    struct timer_list {

    struct list_head entry;         //定时器链表的入口

    unsigned long expires;          //以jiffies为单位的时值

    void (*function)(unsigned long) //定时器处理函数

    unsigned long data;             //定时器处理函数的参数

    struct tvec_t_base_s *base; //定时器内部值

    }

     

    延迟执行:

     

    1、忙等:

    忙等:
    while( time_before(jiffies, timeout) );
    
    忙等变体:
    while( time_before(jiffies, timeout) )
        cond_resched();

    2、内核接口:

    void udelay(…);

    void ndelay(…);

    void mdelay(…);

     

    3、schedule_timeout();

     

  • 相关阅读:
    Java.util.concurrent包学习(一) BlockingQueue接口
    [转载]最牛B的编码套路
    思考人生
    非奇异矩阵的零度互补法则
    Hopfield 网络(下)
    Hopfield 网络(上)
    矩阵的相似性与对角化
    左右特征向量
    特征多项式、代数重数与几何重数
    特征值和特征向量
  • 原文地址:https://www.cnblogs.com/apprentice89/p/2748846.html
Copyright © 2011-2022 走看看