spin_lock and semaphore

spin_lock, mutex, semaphore, wait_queue是几种常见的drive中用的同步与互斥用的方式linux

更多信息能够参考:优化

https://www.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/atom


一. spin_lock实现方式(linux 2.4)

code: include\asm-i386\Spinlock.h
spa

typedef struct {
    volatile unsigned int lock;  //使用volatile修饰,使得编译器每次都从内存读写改值,而不是优化或者忽略,或者使用寄存器中的值
#if SPINLOCK_DEBUG
    unsigned magic;
#endif
} spinlock_t;
static inline void spin_lock(spinlock_t *lock)
{
    "\n1:\t" \
    "lock ; decb %0\n\t" \
    "js 2f\n" \
    ".section .text.lock,\"ax\"\n" \
    "2:\t" \
    "cmpb $0,%0\n\t" \
    "rep;nop\n\t" \
    "jle 2b\n\t" \
    "jmp 1b\n" \
    ".previous"
        :"=m" (lock->lock) : : "memory");
上述代码简略分析:code

1) x86执行Lock指令,在多核处理器中,该指令可以保证某一核可以独占性的处理内存:In a multiprocessor environment, the LOCK# signal insures that the processor has exclusive use of any shared memory while the signal is asserted.
队列

2). lock->lock变量减1 (声明中为volatile变量,则每次都从内存中读取该值,而后减1)ip

3). js 2f: 若是减1以后结果为negative,则跳转到2内存

4). 定义2的符号内容:比较lock->lock与0的大小编译器

5). 若是小于0,则跳转到2同步

6). 不然则跳转到1中

上述执行过程当中对asm的指令解析仍是不彻底正确,可是总的逻辑应该是:执行dec lock->lock,比较是否等于0,若是不等于0,则一直比较,直到等于0,则返回。其中Lock指令应该只在后续的一个执行周期内有效。

从上述代码中能够看出,spin_lock应该适用于多核处理器中的临界变量同步。

关键词:忙等,多处理器

从kernel_locking中的一些关于spin_lock的使用信息:

  1. For kernels compiled withoutCONFIG_SMP, and withoutCONFIG_PREEMPTspinlocks do not exist at all.

  2. You should always test your locking code withCONFIG_SMPandCONFIG_PREEMPTenabled,


二. atomic_add

code: include\asm-i386\Spinlock.h (Linux 2.4)

static __inline__ void atomic_add(int i, atomic_t *v)
{
    __asm__ __volatile__(
        LOCK "addl %1,%0"
        :"=m" (v->counter)
        :"ir" (i), "m" (v->counter));
}
1. 先执行Lock指令,让某一个processor惟一的使用某一内存

2. 执行addl指令

从这个能够看出,这个原子加运算对于多核处理器很是有效,且是原子操做,不会被别的运算打断(只有一条指令)

三. wait_queue_head

code: include\linux\Wait.h (linux 2.4)

struct __wait_queue_head {
    wq_lock_t lock;   //wq_lock_t should be spin_lock

    struct list_head task_list;
};
wait_queue_head表明一个等待队列,其中经过spin_lock或者rwlock_t来完成对列表(list_head task_list)的原子访问. 能够想象全部的操做都是基于list_head与lock的一些操做。

四. semaphore

code: include\asm-i386\Semaphore.h

struct semaphore {
    atomic_t count;
    int sleepers;
    wait_queue_head_t wait;
#endif
};
从kernel-locking中获得的信息:

  1. 若是数据结果仅仅在用户空间使用,应该使用semaphore,而不是spin_lock


五. 关于Preemption:

non-preemption: 除了中断,你能够一直拥有CPU直到用完(ie. you had that CPU until you have it up, except for interrupts). Preemption是在2.5才加进来的。

Preemption: 在用户空间,高优先级任务能够打断正在进行的低优先级任务,spin_lock能够disable preemption.

相关文章
相关标签/搜索