并发和竟态(第五章 )

1、Linux信号量实现:
     (1)直接创建信号量:
     void sema_init(struct semaphore *sem, int val);
     其中val是赋予信号量一个初始的值。
     (2)用下面的方法声明和初始化一个互斥体:
     DECLARE_MUTEX(name);   //一个称为name的信号量被初始化为1
     DECLARE_MUTEX_LOCKED(name);   //一个称为name的信号量被初始化为0
     (3)如果互斥体必须在运行时被初始化,则使用下面的方法:
     void init_MUTEX(struct semaphore *sem);
     void init_MUTEX_LOCKED(struct semaphore *sem);
     (4)P操作:
     void down(struct semaphore *sem);  //必要时一直等待
     int down_interruptable(struct semaphore *sem);  //可中断 
     int down_trylock(struct semaphore *sem);  //永远不会休眠
     (5)V操作:
     void up(struct semaphore *sem);
2、读者/写者信号量:
     (1)必须包含头文件:<linux/rwsem.h>
     (2)一个rwsem信号量在运行时必须用下面的函数显示的初始化:
     void  init_rwsem(struct rw_semaphore *sem);
     (3)只读访问:
     void down_read(struct rw_semaphore *sem);
     int down_read_trylock(struct rw_semaphore *sem);
     void up_read(struct rw_semaphore *sem);
     (4)写入者接口:
     void down_write(struct rw_semaphore *sem);
     int down_write_trylock(struct rw_semaphore *sem);
     void up_write(struct rw_semaphore *sem);
     void downgrade_write(struct rw_semaphore *sem);
3、自旋锁API介绍:
     (1)自旋锁编译阶段的初始化:
     spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
     (2)在运行时调用下面的函数初始化:
     void spin_lock_init(spinlock_t *lock);
     (3)进入临界区之前我们的代码必须调用下面的函数获取需要的锁:
     void spin_lock(spinlock_t *lock);
     (4)释放已经获取的锁:
     void spin_unlock(spinlock_t *lock);
4、 自旋锁的代码都必须是原子的,自旋锁必须在最短的时间内拥有(否则可能会造成优先级翻转)
5、自旋锁函数:
(1)锁定一个自旋锁的函数:
     void spin_lock(spinlock_t *lock);
     void spin_lock_irqsave(spinlock_t *lock, unsigned long flags); //获取自旋锁之前禁止中断,而先前的中断状态保存在flags中。
     void spin_lock_irq(spinlock_t *lock);//如果没有其他任何代码禁止本地中断,则可使用,无需flags
     void spin_lock_bh(spinlock *lock);//禁止软终端,已中断保持打开
(2)释放自旋锁:
     void spin_unlock(spinlock_t *lock);
     void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
     void spin_unlock_irq(spinlock_t *lock);
     void spin_unlock_bh(spinlock_t *lock);
6、读者/写者自旋锁
(1)定义在<linux/spinlock.h>
     rwlock_t my_rwlock = RW_LOCK_UNLOCKED; /*Static way*/
     rwlock_t my_lock;
     rwlock_init(&my_lock); /*Dynamic way*/
(2)读者自旋锁可用操做:
     void read_lock(rwlock_t *lock);
     void read_lock_irqsave(rwlock_t *lock, unsigned long flags);
     void read_lock_irq(rwlock_t *lock);
     void read_lock_bh(rwlock_t *lock);

     void read_unlock(rwlock_t *lock);
     void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags);
     void read_unlock_irq(rwlock_t *lock);
     void read_unlock_bh(rwlock_t *lock);
(3)写者自旋锁可用操作:
     void write_lock(rwlock_t *lock);
     void write_lock_irqsave(rwlock_t *lock, unsigned long flags);
     void write_lock_irq(rwlock_t *lock);
     void write_lock_bh(rwlock_t *lock);
     int write_trylock(rwlock_t *lock);

     void write_unlock(rwlock_t *lock);
     void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags);
     void write_unlock_irq(rwlock_t *lock);
     void write_unlock_bh(rwlock_t *lock);
7、锁陷阱:
     获取局部所和内核锁时,先获得局部锁再获得内核锁;信号量和自旋锁需要先获得信号量再去申请自旋锁,不允许自旋锁去试图获得信号量,因为down(可能导致休眠)。
     如果我们的确怀疑锁竞争导致性能下降,则可以使用lockmeter工具。
8、原子变量:
     定义在<asm/atomic.h>
     类型:atomic_t,在所有内核支持的架构上保存一个int值,但是只能记录不大于24位的整数。
     (1)将原子变量V的值设置成i:
     void atomic_set (stomic_t *V, int i);
     或
     atomic_t V = ATOMIC_INT(0);//编译时初始化V的值。
     (2)返回v的值:
     int atomic_read(atomic_t *v);
     (3)将i累加到v指向的原子变量:
     void atomic_add(int i, atomic_t *v);
     (4)从*v中减去i:
     void atomic_sub(int i, atomic_t *v);
     (5)增加或减去一个原子变量:
     void atomic_inc(atomic_t *v);
     void atomic_dec(atomic_t *v);
     (6)执行特定的操作并测试结果;如果在操作结束后,原子值为0,则返回值为true;否则返回为false。注意,不存在atomic_add_and_test函数。
     int atomic_inc_and_test(atomic_t *v);
     int atomic_dec_and_test(atomic_t *v);
     int atomic_sub_and_test(int i, atomic_t *v);
     (7)将整数值i累加到v。返回值结果为负时为true,否则为false。
     int atomic_add_negative(int i, atomic_t *v);
     (8)类似于atomic_add及其变种,例外之处在于这些函数会将新的值返回给调用者。
     int atomic_add_return(int i, atomic_t *v);
     int atomic_sub_return(int i, atomic_t *v);
     int atomic_inc_return(atomic_t *v);
     int atomic_dec_return(atomic_t *v);
注:要是一个原子操作,则无需加锁,若某个操作中有多个原子操作则需要加锁,因为原子操作之间会隔一段时间。
7、位操作
8、seqlock
(1)需要包含头文件:<linux/seqlock.h>
     初始化seqlock的两种方法:
     seqlock_t lock1 = SEQLOCK_UNLOCKED;
     seqlock_t lock2;
     seqlock_init(&lock2);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值