面试官让你讲讲Linux内核的竞争与并发,你该如何回答?( 三 )
??使用了自旋锁之后可以保证临界区不受别的CPU和本CPU内的抢占进程的打扰 , 但是得到锁的代码在执行临界区的时候 , 还可能受到中断和底半部的影响 , 为了防止这种影响 , 建议使用以下列表中的函数:
文章插图
在多核编程的时候 , 如果进程和中断可能访问同一片临界资源 , 我们一般需要在进程上下文中调用spin_ lock irqsave() spin_unlock_irqrestore() , 在中断上下文中调用 spin_lock() spin _unlock() 。 这样 , 在CPU上 , 无论是进程上下文 , 还是中断上下文获得了自旋锁 , 此后 , 如果CPU1无论是进程上下文 , 还是中断上下文 , 想获得同一自旋锁 , 都必须忙等待 , 这避免一切核间并发的可能性 。 同时 , 由于每个核的进程上下文持有锁的时候用的是 spin_lock_irgsave() , 所以该核上的中断是不可能进入的 , 这避免了核内并发的可能性 。
DEFINE_SPINLOCK(lock) /* 定义并初始化一个锁 */ /* 线程A */void functionA (){ unsigned long flags; /* 中断状态 */ spin_lock_irqsave( if (xxx_count) {/* 已经打开*/ spin_unlock( return -EBUSY; }xxx_count++;/* 增加使用计数*/spin_unlock( ...return 0;/* 成功 */}static int xxx_release(struct inode *inode, struct file *filp){...spinlock(xxx_count--;/* 减少使用计数*/spin_unlock(return 0;}
读写自旋锁??当临界区的一个文件可以被同时读取 , 但是并不能被同时读和写 。 如果一个线程在读 , 另一个线程在写 , 那么很可能会读取到错误的不完整的数据 。 读写自旋锁是可以允许对临界区的共享资源进行并发读操作的 。 但是并不允许多个线程并发读写操作 。 如果想要并发读写 , 就要用到了顺序锁 。??读写自旋锁的读操作函数如下所示:
文章插图
读写自旋锁的写操作函数如下所示:
文章插图
读写锁例程rwlock_t lock; /* 定义rwlock */rwlock_init( /* 初始化rwlock *//* 读时获取锁*/read_lock(... /* 临界资源 */read_unlock(/* 写时获取锁*/write_lock_irqsave(... /* 临界资源 */write_unlock_irqrestore(
顺序锁??顺序锁是读写锁的优化版本 , 读写锁不允许同时读写 , 而使用顺序锁可以完成同时进行读和写的操作 , 但并不允许同时的写 。 虽然顺序锁可以同时进行读写操作 , 但并不建议这样 , 读取的过程并不能保证数据的完整性 。
顺序锁操作函数??顺序锁的读操作函数如下所示:
文章插图
?顺序锁的写操作函数如下所示:
文章插图
自旋锁使用注意事项
- 因为在等待自旋锁的时候处于“自旋”状态 , 因此锁的持有时间不能太长 , 一定要短 , 否则的话会降低系统性能 。 如果临界区比较大 , 运行时间比较长的话要选择其他的并发处理方式 , 比如稍后要讲的信号量和互斥体 。
- 自旋锁保护的临界区内不能调用任何可能导致线程休眠的API函数 , 比如copy_from_user()、copy_to_user()、kmalloc()和msleep()等函数 , 否则的话可能导致死锁 。
- 不能递归申请自旋锁 , 因为一旦通过递归的方式申请一个你正在持有的锁 , 那么你就必须“自旋” , 等待锁被释放 , 然而你正处于“自旋”状态 , 根本没法释放锁 。 结果就是自己把自己锁死了
- 微信还能这么用?让你大开眼界的微信隐藏操作
- 智能水表Pleco将亮相CES:让你全面掌控家庭用水情况
- Honk:让你聊天时不用等待对方回应了
- 千元SKG颈椎按摩仪来了!“九指神器”让你放松
- 牙刷|用电动牙刷的原因有很多,你是什么原因?
- 心灵上的垃圾也需要清理,这六条能不能帮到你,让你不再浮躁
- 功率|充电器太多让你心烦?倍思帮你解决这些烦恼
- 性能还是相机?这四款四千元价位的手机让你两者兼得
- 性能、拍照超“能打”的一加8T 让你把钱全都花在刀刃上
- OPPO Reno5今日开售 前置3200万水光镜让你闪亮