3.并发和竞争

一.概念
1.信号量本质上是一个整数值,
2.Linux内核中几乎所有的信号量均用于互斥。当信号量用于互斥,只能由单个进程或线程拥有。Linux内核中几乎所有的信号量均用于互斥。
3.一个自旋锁是一个互斥设备,只有两个值:“锁定”和“解锁”。如果锁被其他人获得,则代码进入忙循环并重复检查这个锁,直到该锁可用为止。这个循环就是自旋锁的“自旋”。
4.自旋锁用于共享资源较短的地方,一般用于中断
5.锁死,某个获得锁的函数调用其他同样试图获取这个锁的函数,代码就会死锁;不论是信号量还是自旋锁,都不允许锁拥有者第二次获得这个锁,如果试图这么做,系统将挂起。
6.原子操作:就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位。由于操作系统大部分时间处于开中断状态,由于原子操作,则不能被中断的操作。
原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都定义在内核源码树的include/asm/atomic.h文件中,它们都使用汇编语言实现,因为C语言并不能实现这样的操作。
二.常见问题
1.什么是并发
多个进程或线程同时并行的执行某个共享资源。
2.什么是静态。什么情况出现竟态
多个进程或线程同时并行的执行某个共享资源,竞争修改某个资源,容易导致竟态。对称多处理器(SMP)的多个CPU。单CPU内进程与抢占它的进程 。中断(硬中断、软中断、Tasklet、底半部)与进程之间 
3.如何解决竞态问题
保证对共享资源的互斥访问。指一个执行单元在访问共享资源的时候,其他的执行单元被禁止访问。 
4.为什么不能长时间屏蔽中断
不要长时间屏蔽中断,由于Linux系统的异步I/O、进程调度等很多重要操作都依赖于中断,在屏蔽中断期间所有的中断都无法得到处理,因此长时间屏蔽中断是很危险的,有可能造成数据丢失甚至系统崩溃。 
5.读写信号量获取
如果进程已获得3个读信号锁,若希望获取写信号锁则会阻塞,直到3个读信号锁解锁。
如果进程已获得3个读信号锁,如果一个写信号锁已经阻塞,后续进程希望获取读信号锁则也会阻塞,直到写信号锁获取锁并解锁。
6.自旋锁的使用规则
任何拥有自旋锁的代码都必须是原子的;如果中断处理函数中也要获得自选锁,那么驱动程序需要在拥有自旋锁时禁止中断;自旋锁必须在可能的最短时间内拥有;
7.如何避免锁死
按同样的顺序获得锁,如果必须获得一个局部锁和一个属于内核更中心位置的锁,则应该首先获取自己的局部锁 ,如果我们拥有信号量和自旋锁的组合,则必须首先获得信号量;在拥有自旋锁时调用down(可导致休眠)是个严重的错误的 
8.信号量VS自旋锁
开销成本:使用信号量的开销是进程上下文切换时间,自旋锁的开销是忙等待获取自旋锁一直占用CPU。
等待机制不同:信号量可能导致阻塞,所以在不允许阻塞的代码中不能用可能引起阻塞的信号量处理方式,自旋锁是忙等待,不会引起调用者睡眠。因为自旋锁不会引起调用者睡眠,所以自旋锁的效率远高于互斥锁。比如,中断处理程序不允许阻塞。

三.驱动模块功能相关的结构体
1.中断屏蔽:
中断屏蔽作用:可解决中断与进程之间的并发,也可解决内核抢占进程之间的并发。
成员函数:
初始化:
功能函数;使能和屏蔽中断
a.使能中断
local_irq_enable()          //打开中断
local_bh_enable()           //仅打开中断底半部中断
local_irq_restore(flags)    //打开中断,并恢复flags里的值到中断寄存器
b.屏蔽中断
local_irq_disable()         //禁止中断
local_bh_disable()          //仅禁止中断底半部中断
local_irq_save(flags)       //禁止中断并保存中断寄存器信息到flags
释放资源:

2.struct semaphore:信号量
struct semaphore作用:用于保护临界资源的互斥。也可以进行同步。Linux内核中几乎所有的信号量均用于互斥。互斥锁不能用于中断上下文。
成员函数:
初始化:
a.静态
DECLARE_MUTEX(name);//静态定义和初始化互斥体为1
DECLARE_MUTEX_LOCKED(name); //静态定义和初始化互斥体为0
b.动态
void sema_init(struct semaphore *sem,int val); //动态初始化信号量为任意值。
void init_MUTEX(struct semaphore *sem);//动态初始化互斥体为1
void init_MUTEX_LOCKED(struct semaphore *sem);//动态初始化互斥体为0
功能函数:实现获取和释放信号量,从而实现资源的互斥操作。
a.获取信号量
void down(struct semaphore *sem);//本质减小信号量的值。
int down_interruptible(struct semaphore *sem);//和down完成相同的工作,但操作可中断。
int down_trylock(struct semaphore *sem);//尝试获取锁,永远不会休眠,如果信号量在调用时不可获得, 就会立即返回一个非零值。
b.释放信号量
void up(struct semaphore *sem);//本质增加信号量的值。。
释放资源:

3.struct spinlock(spinlock_t):自旋锁
struct spinlock(spinlock_t)作用:多用于中断中,不能用于临界资源代码中有阻塞函数。保护临界资源的互斥 。
成员函数:
初始化:
a.静态
spinlock_t xxx_lock=SPIN_LOCK_UNLOCKED;
b.动态
void spin_lock_init(spinlock_t *lock);
功能函数:锁定和解锁
a.锁定
void spin_lock(spinlock_t *lock);
void spin_trylock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock,unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock);
b.解锁
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);
释放资源:

4.struct completion:完成量
struct completion作用:用于同步,一种轻量级的机制,它允许一个线程告诉另一线程某个工作已经完成。
成员函数:#include <linux/spinlock.h>
初始化:
a.静态
DECLARE_COMPLETION(xxx_completion);//带初始化,done = 0;
b.动态
struct completion xxx_completion;
init_completion(&xxx_completion);
功能函数:等待和触发,从而完成同步
a.等待completion
void wait_for_completion(struct completion *c); //等待某个事件完成。
b.触发completion
void complete(struct completion *c);//表示某个事件完成。
void complete_all(struct completion *c);
释放资源:

5.atomic_t :整形原子操作
atomic_t作用:用于使用设备只能被一个进程打开,用在open函数中,实现内核的原子操作。
成员函数:#include <linux/types.h>
初始化:
a.静态
atomic_t v = ATOMIC_INIT(0);
b.动态
void atomic_set(atomic_t *v,int i);
功能函数:atomic_t加减,实现原子操作。
a.原子变量自增/自减
void atomic_inc(atomic_t *v);//在release中调用释放设备
void atomic_dec(atomic_t *v);
b.原子变量加/减
void atomic_add(int i,atomic_t *v);
void atomic_sub(int i,atomic_t *v);
c.获取原子变量的值
int atomic_read(atomic_t *v);
d.操作并测试
int atomic_inc_and_test(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);//在open中调用实现设备只能被一个进程打开
int atomic_sub_and_test(int i,atomic_t *v);
e.操作并返回
int atomic_inc_return(atomic_t *v);
int atomic_dec_return(atomic_t *v);
int atomic_add_return(int i,atomic_t *v);
int atomic_sub_return(int i,atomic_t *v);
释放资源:

6.struct rw_semaphore:读写信号量
struct rw_semaphore作用:提高信号量的效率。对于读写信号量可以实现同时多个进程或线程读取,同时一个线程或进程写。
成员函数:
初始化:
a.动态
void init_rwsem(struct rw_semaphore *sem);
功能函数:实现获取和释放信号量,从而实现临界资源的互斥操作。
a.读信号量获取
void down_read(struct rw_semaphore *sem);//获取读锁。
int down_read_trylock(struct rw_semaphore *sem); //尝试获取读锁,永远不会休眠,如果信号量在调用时不可获得, 就会立即返回一个非零值。
b.读信号量释放
void up_read(struct rw_semaphore *sem);//释放读锁
c.写信号量获取
void down_write(struct rw_semaphore *sem);//获取写锁。
int down_write_trylock(struct rw_semaphore *sem);//尝试获取写锁,永远不会休眠,如果信号量在调用时不可获得, 就会立即返回一个非零值。
d.写信号量释放
void up_write(struct rw_semaphore *sem);//释放写锁
void downgrade_write(struct rw_semaphore *sem);
释放资源:

7.rwlock_t:读写自旋锁
rwlock_t作用:提高自旋锁的效率。对于读写自旋锁可以实现同时多个进程或线程读加锁,同时一个线程或进程写加锁。
成员函数:
初始化:
a.静态
rwlock_t xxx_rwlock = RW_LOCK_UNLOCKED;
b.动态
rwlock_t xxx_rwlock;
rwlock_init(&xxx_rwlock); 
功能函数:读写锁锁定和读写锁解锁
a.读锁锁定
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);
b.读锁解锁
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);
c.写锁锁定
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);
d.写锁释放
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);
释放资源:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值