一、并发与竞争
linux是一个多任务的系统。多任务就存在抢占,抢占资源。但是不可以同时抢占,否则会产生混乱。因此,我们要保护资源,那么什么是资源呢?资源就是共享资源,就是一系列的变量存取的数据。
并发与竞争的处理方法
1.原子操作
原子操作简单说一下,就是程序只执行一句汇编。向自增,编译以后会执行三步,就肯定不是原子操作了。
竞争与并发为什么要提及原子操作呢?是因为,如果在多任务中,现在我们有两个任务。任务①自增变量a , 此时任务②也执行自增变量a,那么就会得到混乱的程序。
原子操作的API函数。
1.申请变量在linux/types.h中。
typedef struct {
int counter;
} atomic_t;
atomic_t a; //定义变量
a = ATOMIC_INIT(0); //初始化
2.include/asm/atomic.h中的API
包括加减乘除,置位复位等。
2.自旋锁
一个锁适用于保护资源的。当一个任务要访问共享资源,就要申请自旋锁,当其他线程想要访问资源的时候,就要原地打转进入等待状态。只有当任务释放锁以后,其他任务才可以申请该锁。
一定不能使用使得CPU引起休眠或者阻塞的程序,否则会造成死锁。情景复现:当testA上锁后,调用休眠程序,如果再此期间,testB的权限比testA高,也想抢占锁的话,CPU就会离开testA的程序,B既无法抢占锁,程序就会卡在这里,造成死锁。
由上段的情景,我们的线程内有锁的话,中断也有锁的话,也容易产生死锁。因为中断时可以直接打断线程的,它比线程的优先级高。所以也要注意这种情况的发生。所以我们可以使用禁止本地中断上锁的函数API。spin_lock_irq(spinlock_t lock); 。但是中断太多,无法确保,就使用**spin_lock_irqsave(spinlock_t lock,unsigned long flags); 函数。
注意:自旋锁只适合于短时间的加锁,如果长时间的加锁会降低系统性能。如果想要长时间持锁,就要换其他办法。
typedef struct spinlock {
union {
struct raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct {
u8 __padding[LOCK_PADSIZE];
struct lockdep_map dep_map;
};
#endif
};
} spinlock_t;
2.spinlock API
int spin_lock_init(_lock); //申请锁
void spin_lock(spinlock_t *lock); //上锁
void spin_unlock(spinlock_t *lock); //释放锁
int spin_trylock(spinlock_t *lock); //尝试上锁
//处理中断中的锁函数
void spin_lock_irq(spinlock_t *lock);//禁止中断上锁
void spin_unlock_irq(spinlock_t *lock);//释放本地中断上锁
void spin_lock_irqsave(spinlock_t *lock,unsigned long flags);
void spin_unlock_irqsave(spinlock_t *lock,unsigned long flags);
//api中带bh的后缀是中断下半部
...
3,信号量
如果临界区比较大的话,使用信号量。信号量可以使得线程进入休眠状态。因此,信号量可以适合于资源比较久的场合。它不能使用与中断,因为会使得休眠,而我们不能让中断休眠。
信号量的效果:如果多任务处理,每一个任务都会处理到,只不过会有一个先后过程,而不会向自旋锁一样不让执行。
持有资源时间较短不适合信号量是因为频繁切换线程,使得线程休眠是划不来的,开销要大。
semaphore.h
struct semaphore {
raw_spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
static inline void sema_init(struct semaphore *sem, int val);
extern void down(struct semaphore *sem); //申请信号量
extern int __must_check down_interruptible(struct semaphore *sem);
extern int __must_check down_killable(struct semaphore *sem);
extern int __must_check down_trylock(struct semaphore *sem);
extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
extern void up(struct semaphore *sem); //释放信号量
4.互斥体
mutex,和信号量一样。用于阻塞线程的。首选它。其他文档有详细写它。
\