Linux中的并发和竞态

本帖大体上描述Linux kernel为解决并发导致的竞态所提供的内核API(主要是信号量和自旋锁)之间的区别,侧重于使用方面。代码级的阅读比较打算另开一贴。
因为程序的并发执行而导致的竞态是Linux内核中一个非常复杂的方面。对于设备的驱动程序开发者而言,熟悉Linux内核提供的并发互斥的处理机制相当重要。所谓竞态,简而言之,是多个内核线程有可能对同一资源进行操作时可能导致的内核数据紊乱的行为。共享数据是并发的根本原因。
并发的来源—
我把并发来源分为两个大的方面来分别进行讨论:单处理器和多处理器。
1.单处理器
对于单处理器而言,并发主要来自于中断,可抢占的内核和各种延迟队列。
2.多处理器
多处理器的情况更加复杂,在同一时间,同一代码可同时在不同处理器上执行。对这种并发的处理要更加棘手。
内核的互斥设施—
驱动程序开发者对内核提供的互斥机制的确切理解是写出高安全性代码的关键。在Linux内核中,这种设施主要是信号量和自旋锁。
1.信号量
信号量的原理主要是基于对一内存单元的原子性的测试和设置操作(atomic test and set),不同处理器有不同的汇编语言用于提供这种机制。因为内存单元对于多处理器系统中的每个处理器都是共享的,所以这种机制同样适用于多处理器。
相对于自选锁,信号量的最大特点是允许调用它的线程进入睡眠状态。这意味着试图获得某一信号量的线程会导致对处理器拥有权的丧失,也即出现进程的切换。
2.自旋锁
自旋锁的出现最初是为了解决多处理器上出现的互斥问题。其原理是,试图获得锁的线程去进行原子性的位测试和设置操作(atomic bit test and set),如果没有别的处理器进入临界区,那么当前线程将获得锁,锁定之后进入临界区。如果有别的处理器在临界区中,那么当前处理器将进入忙等待状态,直到其他处理器解开该锁。与信号量最大的区别是,试图进入临界区的线程如果得不到锁,那么就一直不停地执行atomic bit test操作而不会进入睡眠状态。这种情况下,试图获得锁的处理器上将啥工作也干不了(除了进行这种atomic bit test操作外),正因为如此,所以要求获得锁的线程要以最短的时间结束临界区中的操作。
在单处理器上,自旋锁更确切的意义是,一个试图获得锁的线程实际上是向系统通告:当我执行下面代码时,不要将我切换出处理器。因此,单处理器上的自旋锁代码实际是在完成对处理器的强制拥有的操作。而在单处理器上,中断和抢占是最大可能的并发源头,所以,实际上单处理器上的自旋锁的实现代码简单归结为:关中断和关闭抢占。理解spin lock的实现代码需要深刻的处理器相关知识和汇编语言。
基于以上的实现原理,使用自旋锁的一个核心规则是:拥有锁的线程绝对不可以放弃处理器。因为假设它放弃了处理器,那么另一个获得处理器线程的代码如果想获得该锁,将不得不等待很长的时间,更坏的情况下导致系统的死锁。更具体的描述:在单处理器上,一个获得锁的线程必然运行在中断和抢占都关闭的环境中,这种情况下被动的放弃处理器已经成为不可能,只有主动放弃处理器才会出现,比如在互斥代码中调用了copy_from_user,该函数的实现中使进程进入休眠成为可能,如果恰巧下一个被调度运行的线程试图获得该锁,那么系统将进入死锁状态,因为这种情况下后来被调度的线程已经没有主动放弃处理器的可能(因为它此时正运行试图获得锁的代码,不可能调用到那些有可能主动放弃处理器的函数)。具体的例子:
假设系统中有A和B两个线程,当A线程执行到下面的代码时将可能会丢失处理器:
spinlock_t   g_lock = SPIN_LOCK_UNLOCKED;  //一个全局的spin_lock 变量
A代码:
spin_lock_init(&g_lock);
spin_lock (&g_lock);
copy_from_user(…);  //A线程在该函数中失去处理器的拥有权
被调度执行的B线程代码:

spin_lock (&g_lock); //因为已经休眠的A线程没有释放g_lock,所以B线程将永远在此处自旋下去。注意此时中断和抢占都是关闭的,即被动放弃处理器已经不可能。
互斥问题的复杂性恰恰就在这里:休眠可发生在许多无法预期的地方。因此当我们编写需要在自旋锁下执行的代码时,必须注意每一个所调用的函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值