Linux中的同步问题(Linux驱动1)

操作系统中存在竞态问题,就是同时访问共享资源(包括程序,数据),引起竞态的原因有:smp,抢占式内核,中断(硬中断,软中断等).
抢占式内核竞态问题的图示:
假如代码如下:
write(resource);
write_count++;

A进程             B进程             C进程
------------------------------------------------------
写               
------------------------------------------------------
                    写
-----------------------------------------------------                   
计数  =1          
------------------------------------------------
                                  读计数(这时,就有问题)
-----------------------------------------------------                                       
                    计数=2
---------------------------------------------------             

问题:进程c读计数时,实际写了两次,可是这里读计数只有1次,问题产生的原因就在于写和计数不是原子操作)。

保护共享资源的方法有:中断屏蔽,原子操作,锁,信号量.

1 中断屏蔽

变量
函数
    local_irq_enable
    local_irq_disable
用法
    local_irq_disable
    ....
    local_irq_enable

扩展:
    local_irq_save(flags)
    local_irq_restore(flags)

    local_bh_enable
    local_bh_disable

2原子操作

说明:原子操作,不会被打断
变量:
    atomic_t 
    ATOMIT_INIT(i)  初始化值
函数
    atomic_inc(atomic_t*)
    atomic_dec(atomic_t*)

    atomic_add(int,atomic_t*)
    atomic_sub(int,atomic_t*)

    atomic_read(atomic_t*)

    atomic_inc_and_test(atomic_t*)
    atomic_dec_and_test(atomic_t*)
    atomic_sub_and_test(int,atomic_t*) 注意,没有加

    atomic_inc_return(atomic_t*)
    atomic_dec_return(atomic_t*)
    atomic_add_return(int,atomic_t*)
    atomic_sub_return(int,atomic_t*)

    bit操作
    set_bit(nr,void*)
    clear_bit(nr,void*)
    change_bit(nr,void*)

    test_bit(nr,void*)

    test_and_set(nr,void*) 先测试,再操作
    test_and_clear(nr,void*)
    test_and_change(nr,void*)

3 自旋锁

说明:
    自旋锁会在原地打转,所以临界区尽可能短,不能阻塞.
变量:
    spinlock_t lock

函数
    spin_lock_init(spinlock_t*)

    spin_lock(spinlock_t*)
    spin_unlock(spinlock_t*)
用法
    spinlock_t lock
    spin_lock_init(&lock)
    spin_lock(&lock)
    ...
    spin_unlock(&lock)
扩展
    spin_trylock(&lock)

    spin_lock_irq(&lock)
    spin_unlock_irq(&lock)

    spin_lock_irqsave(&lock,flags)
    spin_unlock_irqrestore(&lock,flags)

    spin_lock_bh(&lock)
    spin_unlock_bh(&lock)

    读写自旋锁

说明:读写锁是比自旋锁粒度更小的锁,自旋锁对于读写不加区分,而实际上对于读操作是可以并发的,读写锁就是解决这个问题。当然,读和写也是不能同时进行的。

        变量:
            rwlock_t lock=RW_LOCK_UNLOCKED;静态初始化

        函数
            rwlock_init(rwlock_t*)动态初始化

            read_lock(rwlock_t*)
            read_unlock(rwlock_t*)
            write_lock(rwlock_t*)
            write_unlock(rwlock_t*)
        用法
            rwlock_t lock;
            rwlock_init(&lock)
            读自旋锁
            read_lock(&lock)
            ...
            read_unlock(&lock)

            写自旋锁
            write_lock(&lock)
            ...
            write_unlock(&lock)

        扩展
            read_lock_irq(&lock)
            read_unlock_irq(&lock)

            read_lock_irqsave(&lock,flags)
            read_unlock_irqrestore(&lock,flags)

            read_lock_bh(&lock)
            read_unlock_bh(&lock)

            write_lock_irq(&lock)
            write_unlock_irq(&lock)

            write_lock_irqsave(&lock,flags)
            write_unlock_irqrestore(&lock,flags)

            write_lock_bh(&lock)
            write_unlock_bh(&lock)

4 顺序锁

说明:顺序锁是读写锁的优化,读单元不会被写单元阻塞,写单元也不会被读单元阻塞。但是写单元之间仍然是互斥的。顺序锁有一个限制就是不能在其中使用指针,因为在保护的写单元中可能会使指针失效,而读单元此时使用指针就会失效。

        变量:
            seqlock_t lock;
        函数:
            write_seqlock(&lock)
            write_sequnlock(&lock)
            write_seqtrylock(&lock)

            read_seqbegin(&lock)
            read_seqretry(&lock,iv)
        用法:
            写操作
            write_seqlock
            ...
            write_sequnlock

            读操作
            do{
                seqnum=read_seqbegin(&lock);
                ....
            }while(read_seqretry(&lock,sequm))
        扩展:
            write_seqlock_irq(&lock)
            write_sequnlock_irq(&lock)

            write_seqlock_irqsave(&lock,falgs)
            write_sequnlock_irqrestore(&lock,falgs)

            write_seqlock_bh(&lock)
            write_sequnlock_bh(&lock)

            read_seqbegin_irqsave(&lock,falgs)
            read_seqretry_irqrestore(&lock,iv,flags)

6 RCU

说明:rcu是read copy update的意思,可以看做是读写锁的高级版本,可以对保护单元同时进行读写.

        变量:rcu_head head
        函数:
            read_lock_rcu()
            read_unlock_rcu()
            call_rcu(struct rcu_head*,void(*fun)(struct rcu_head*))

        用法:
            read_lock_rcu
            ...
            read_unlock_rcu

        扩展
            list_add_rcu
            list_add_tail_rcu
            list_del_rcu
            list_replace_rcu
            list_for_each_rcu
            list_for_each_safe_rcu
            list_for_each_entry_rcu

            hlist_add_head_rcu
            hlist_del_rcu
            hlist_for_each_rcu
            hlost_for_each_entry_rcu

7 信号量

说明:
    信号量与自旋锁不同,信号量会进入休眠状态,而自旋锁会在原地打转.            
变量:
    semaphore sem;
函数:
    sema_init(struct semaphore *,int val)

    DECLARE_MUTEX(name)
    DECLARE_MUTEX_LOCKED(name)
    init_MUTEX(&sem)
    init_MUTEX_LOCKED(&sem)

    down(&sem)
    up(&sem)
用法:
    down
    ....
    up

扩展:

down_interruptible(&sem) 进入浅睡眠状态,可被打断.当调用此函数时需要检查其返回值如果返回非0,应当返回-ERESTARTSYS
down_trylock 尝试获得信号量,如果获得则立即返回0,否则返回非零值,此函数不会引起睡眠.

8 读写信号量

        说明:
            读写信号量与信号量的关系与读写锁与自旋锁的关系是一样的.
        变量:
            rw_semaphore sem
        函数:
            init_rwsem(&sem)

            down_read
            up_read
            down_read_trylock

            down_write
            up_write
            down_write_trylock
    完成量
        说明:
            完成量是为了同步两个进程.
        变量:
            completion comp;
        函数:
            init_completion(&comp);
            DECLARE_COMPLETION(name)

            wait_for_completion
            complete
            complete_all
        用法:
            进程A                     进程B
            wait_for_completion         complete

10 互斥体

说明:
    互斥体与信号量是一样的.
变量:
    mutex mux;
函数:
    mutex_init(&mux)

    mutex_lock
    mutex_unlock

    mutex_trylock
    mutex_lock_interruptible    
用法:
    mutex_lock
    ...
    mutex_unlock
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值