Linux驱动开发4——并发和竞态
Linux系统处于一个高并发的运行环境,不管是系统调用还是中断都要求可重入,但是有一些系统资源处于临界区,因此,必须保证临界区资源访问的原子性。 对于临界区资源被占用时,发起访问的进程,有三种处理方法——睡眠、阻塞以及撤销。 Linux驱动编程中,通常不建议使用锁机制,因为容易导致死锁问题。不使用锁的场景,尽量使用kfifo缓冲队列来存取数据;在必须使用锁的场景,建议使用信号量和自旋锁。 信号量通常用在可以睡眠的场景,如进程上下文;而自旋锁通常用在不可睡眠的场景,如中断上下文。 ? 1、信号量 #include <asm/semaphore.h> 信号量初始化 void sema_init(struct semaphore *sem,int val); 互斥信号量 DECLARE_MUTEX(name); DECLARE_MUTEX_LOCKED(name); void init_MUTEX(struct semaphore *sem); void init_MUTEX_LOCKED(struct semaphore *sem); 获取信号量 void down(struct semaphore *sem); int down_interruptible(struct semaphore *sem); /* 可中断,即进入睡眠状态等待信号量,需要一直检查返回值并且针对性地响应 */ int down_trylock(struct semaphore *sem); /* 从不睡眠,如果信号量被占用,立刻返回 */ 释放信号量 void up(struct semaphore *sem); ?示例: if (down_interruptible(&sem)) return -ERESTARTSYS; ? 1.1、读写信号量 由信号量衍生,可以允许多个用户并发读,一个用户互斥写。 #include <linux/rwsem.h> /* 初始化 */ void init_rwsem(struct rw_semaphore *sem); /* 读者接口 */ void down_read(struct rw_semaphore *sem); void down_read_trylock(struct rw_semaphore *sem); void up_read(struct rw_semaphore *sem); /* 写者接口 */ void down_write(struct rw_semaphore *sem); void down_write_trylock(struct rw_semaphore *sem); void up_write(struct rw_semaphore *sem); ? 2、自旋锁 #include <linux/spinlock.h> 初始化 spinlock_t my_lock = SPIN_LOCK_UNLOCKED; 或者 void spin_lock_init(spinlock_t *lock); 获取自旋锁 void spin_lock(spinlock_t *lock); 释放自旋锁 void spin_unlock(spinlock_t *lock); ? 2.1、读写自旋锁 类似于读写信号量,读写自旋锁是自旋锁的衍生。 ? 3、原子量(atomic) ? 4、顺序锁(seqlock) 顺序锁用来保护较小的资源,快速存取的场景。它允许读者释放对资源的存取,但是要求读者检查与写者的冲突,如果发生冲突,重试存取操作。 seqlock通常不能用在保护包含指针的数据结构,因为读者可能跟随一个无效指针而写者在改变数据结构。 #include <linux/seqlock.h> seqlock_init(seqlock_t *lock); ? 5、读取-拷贝-更新(RCU) 一种高级的互斥方法 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |