单核与多核上锁的区别

参考:1、《Linux Kernel Development》3ed_CN  p131-p140

            2、2.6.34

单核:

//锁的数据类型实现
typedef struct { } arch_spinlock_t;



typedef struct raw_spinlock {

    arch_spinlock_t raw_lock;

}raw_spinlock_t;



typedef struct spinlock {

    union {

        struct raw_spinlock rlock;

    }; //以我对C的了解,这种定义方式还是第一次见到(以前见到,也没留意过),这个union的联合体的最后竟然没有变量名称,即union {xxxxx} var_name; gcc后指定为c89标准也能正常编译与运行
       //还有就是可以通过&lock->rlock,直接获得访问rlock的地址, 原来都是通过&lock->var_name.rlock来操作完成
       //此处加个变量名,反而显得累赘,而且如果加上变量明就必须通过变量名访问。 }spinlock_t;
//锁是空的

 

 

//spin_lock的实现

#define __acquire(x) (void)0

#define __LOCK(lock) \

    do {preempt_disable(); __acquire(lock); (void)(lock); } while(0)

#define _raw_spin_lock(lock) __LOCK(lock)

#define raw_spin_lock(lock) _raw_spin_lock(lock)





static inline void spin_lock(spinlock_t *lock)

{

    raw_spin_lock(&lock->rlock);

}
 
   

//单核是否支持抢占在锁上的区别:

#ifdef CONFIG_PREEMPT

#define preempt_disable() \

    do{ \

        inc_preempt_count(); \

        barrier(); \

    } while(0)

#else

#define preempt_disable() do { } while(0)

 

多核:

//锁的数据类型实现
typedef struct {

    volatile unsigned int lock;

} arch_spinlock_t;



typedef struct raw_spinlock {

    arch_spinlock_t raw_lock;

} raw_spinlock_t;



typedef struct spinlock {

    union {

        struct raw_spinlock rlock;

    };

} spinlock_t;

 

//spin_lock的实现

static inline void arch_spin_lock(arch_spinlock_t *lock)

{

    unsigned long tmp;



    __asm__ __volatile__(

    "1: ldrex   %0, [%1]      \n\t"

    "   teq     %0, #0        \n\t"

    "   strexeq %0, %2, [%1]  \n\t"

    "   teqeq   %0, #0        \n\t"

    "   bne     1b                "

    : "=&r" (tmp)

    : "r" (&lock->lock), "r"(1)

    : "cc"

    smp_mb();

}



static inline void do_raw_spin_lock(raw_spinlock_t *lock)

{

    arch_spin_lock(&lock->raw_lock);

}



static inline void __raw_spin_lock(raw_spinlock_t *lock)

{

    preempt_disable();

    do_raw_spin_lock(lock);

}



static inline void spin_lock(spinlock_t *lock)

{

    raw_spin_lock(&lock->rlock);

}

 

附:

1、同步,锁的问题,我认为发生在(1)进程与进程之间;  (2)中断与进程之间;  (3)中断与中断之间(细分上半部、下半部)

1)如果进程上下文核一个下半部共享数据,在访问这些数据之前,需要禁止下半部的处理并得到锁的使用权。做这些是为了本地和SMP的保护并且防止死锁的出现。(p_128)



(2)如果中断上下文和一个下半部共享数据,在访问数据之前,需要禁止禁止中断并得到锁的使用权。做这些是为了本地和SMP的保护并且防止死锁的出现。(p_128)



(3)如若在一段内核代码操作某资源的时候系统产生了一个中断,而该中断的处理程序还要访问这一个资源,这就是一个bug。(p_135最后)



    关于(3),经讨论使用出使用spin_lock_irqsave;

    其它的也应有拌饭解决,以后会讲明。

 

2、记下书中提出的几条建议:

1)最开始设计的时候就要考虑加入锁,而不是事后才想到。如果代码已经写好,再在其中找到需要上锁的部分并向其中追加锁,是非常困难的,结果也往往也不尽如人意。避免这种亡羊补牢的做法是:在编写代码的开始阶段就要设计恰当的锁。(p_136中间)



(2lock contention(锁的争用):是指当锁正在被占用时,有其它线程试图获得该锁。锁处于高度争用的状态是指有多个其他线程在等待获得该锁。(p_138最后)



(3)被保护数据的规模描述了锁的粒度,细粒度的锁保护小块数据,过粗的锁保护大块数据。(p_139中间)                       

    当锁争用严重时,加锁太粗会降低可扩展性;而锁争用不明显时,加锁过细会加大系统开销,带来浪费,这两种情况都会造成系统性能下降。(p_139最后)

 

还是谈下spin_unlock,不然总缺了什么。

单核上:

static inline void spin_unlock(spinlock_t *lock)

{

        raw_spin_unlock(&lock->rlock);                                                                             

}



#define raw_spin_unlock(lock)           _raw_spin_unlock(lock)                                                     



#define _raw_spin_unlock(lock)                  __UNLOCK(lock)                                             



#define __UNLOCK(lock) \                                                                                           

  do { preempt_enable(); __release(lock); (void)(lock); } while (0)



#ifdef CONFIG_PREEMPT



#define preempt_enable_no_resched() \                                                                              

do { \

        barrier(); \

        dec_preempt_count(); \

} while (0)





#define preempt_check_resched() \                                                                                  

do { \

        if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \

                preempt_schedule(); \

} while (0)



//可能触发内核态抢占

#define preempt_enable() \

do { \

        preempt_enable_no_resched(); \

        barrier(); \

        preempt_check_resched(); \

} while (0)    



#else



#define preempt_enable()                do { } while (0)                                                           



#endif                                                                                                    

 

 多核:

static inline void spin_unlock(spinlock_t *lock)

{

        raw_spin_unlock(&lock->rlock);                                                                             

}



#define raw_spin_unlock(lock)           _raw_spin_unlock(lock)                                                     



#define _raw_spin_unlock(lock) __raw_spin_unlock(lock)     



static inline void dsb_sev(void)                                                                                   

{

        __asm__ __volatile__ (

                "dsb\n"

                "sev"

        );

}

 

static inline void arch_spin_unlock(arch_spinlock_t *lock)                                                         

{

        smp_mb();



        __asm__ __volatile__(

"       str     %1, [%0]\n"

        :       

        : "r" (&lock->lock), "r" (0)

        : "cc");

                

        dsb_sev();

}       



void do_raw_spin_unlock(raw_spinlock_t *lock)                                                                      

{

//        debug_spin_unlock(lock);

        arch_spin_unlock(&lock->raw_lock);

}



static inline void __raw_spin_unlock(raw_spinlock_t *lock)                                                         

{

//        spin_release(&lock->dep_map, 1, _RET_IP_);

        do_raw_spin_unlock(lock);

        preempt_enable(); //与单核抢占情形相同

}

你可能感兴趣的:(区别)