A. 如何利用信号量机制实现多进程访问临界资源
进程互斥 定义:两个或两个以上的进程,不能同时进入关于同一组共享变量的临界区域,否则可能发生与时间有关的错误,这种现象被称作进程互斥.
在多道程序环境下,存在着临界资源,它是指多进程存在时必须互斥访问的资源。也就是某一时刻不允许多个进程同时访问,只能单个进程的访问。我们把这些程序的片段称作临界区或临界段,它存在的目的是有效的防止竞争条件又能保证最大化使用共享数据。而这些并发进程必须有好的解决方案,才能防止出现以下情况:多个进程同时处于临界区,临界区外的进程阻塞其他的进程,有些进程在临界区外无休止的等待。除此以外,这些方案还不能对CPU的速度和数目做出任何的假设。只有满足了这些条件,才是一个好的解决方案。
访问临界资源的循环进程可以这样来描述:
Repeat
entry section
Critical sections;
exit section
Remainder sectioni;
Until false
为实现进程互斥,可以利用软件的方法,也可以在系统中设置专门的同步机制来协调多个进程,但是所有的同步机制应该遵循四大准则:
1.空闲让进 当临界资源处于空闲状态,允许一个请求进入临界区的进程立即进入临界区,从 而有效的利用资源。
2.忙则等待 已经有进程进入临界区时,意味着相应的临界资源正在被访问,所以其他准备进 入临界区的进程必须等待,来保证多进程互斥。
3.有限等待 对要求访问临界资源的进程,应该保证该进程能在有效的时间内进入临界区,防 止死等状态。
4.让权等待 当进程不能进入临界区,应该立即释放处理机,防止进程忙等待。
早期解决进程互斥问题有软件的方法和硬件的方法,如:严格轮换法,Peterson的解决方案,TSL指令,Swap指令都可以实现进程的互斥,不过它们都有一定的缺陷,这里就不一一详细说明,而后来Kijkstra提出的信号量机制则更好的解决了互斥问题。
B. Linux系统中对临界资源进行互斥访问的手段是
自旋锁(Spin Lock)是一种典型的对临界资源进行互斥访问的手段,其名称来源于它的工作方式。为了获得一个自旋锁,在某CPU上运行的代码需先执行一个原子操作,该操作测试并设置(Test-AndSet)某个内存变量。由于它是原子操作,所以在该操作完成之前其他执行单元不可能访问这个内存变量。如果测试结果表明锁已经空闲,则程序获得这个自旋锁并继续执行;如果测试结果表明锁仍被占用,程序将在一个小的循环内重复这个“测试并设置”操作,即进行所谓的“自旋”,通俗地说就是“在原地打转”。当自旋锁的持有者通过重置该变量释放这个自旋锁后,某个等待的“测试并设置”操作向其调用者报告锁已释放。理解自旋锁最简单的方法是把它作为一个变量看待,该变量把一个临界区标记为“我当前在运行,请稍等一会”或者标记为“我当前不在运行,可以被使用。如果A执行单元首先进入例程,它将持有自旋锁;当B执行单元试图进入同一个例程时,将获知自旋锁已被持有,需等到A执行单元释放后才能进入。在ARM体系结构下,自旋锁的实现借用了ldrex指令、strex指令、ARM处理器内存屏障指令dmb和dsb、wfe指令和sev指令,这类似于代码清单7.1的逻辑。可以说既要保证排他性,也要处理好内存屏障。
自旋锁主要针对SMP或单CPU但内核可抢占的情况,对于单CPU和内核不支持抢占的系统,自旋锁退化为空操作。在单CPU和内核可抢占的系统中,自旋锁持有期间中内核的抢占将被禁止。由于内核可抢占的单CPU系统的行为实际上很类似于SMP系统,因此,在这样的单CPU系统中使用自旋锁仍十分必要。另外,在多核SMP的情况下,任何一个核拿到了自旋锁,该核上的抢占调度也暂时禁止了,但是没有禁止另外一个核的抢占调度。尽管用了自旋锁可以保证临界区不受别的CPU和本CPU内的抢占进程打扰,但是得到锁的代码路径在执行临界区的时候,还可能受到中断和底半部的影响。为了防止这种影响,就需要用到自旋锁的衍生。
C. 为什么多个进程临界资源的访问必须互斥
互斥就是以某种手段保证只有一个进程访问共享资源。就是说要保证两个或以上进程不会同时处于临界区。
互斥方案四要求:
1.不应该对CPU数目,速度作任何假设;
2.临界区外的进程不得阻塞其他进程进入临界区;
3.只能一个进程进入临界区;
4.申请进入临界区的进程不能无限等待。
http://ke..com/view/281245.htm 这里可以参考下
D. 实现临界区互斥的方法
实现临界区互斥的方法主要有三种:软件方法、硬件支持的方法、信号量方法。
首先,我们来看软件方法。Peterson算法是一种经典的软件解决互斥问题的方法。它通过设置两个标志数组和一个共享变量来实现进程间的互斥。每个进程在进入临界区前会先设置自己的标志为想要进入临界区,并检查其他进程的标志。如果其他进程没有要求进入临界区,则当前进程可以进入。为了避免两个进程同时检查到对方没有要求进入临界区而同时进入的情况,Peterson算法引入了一个共享变量,用来确保只有一个进程能够进入临界区。
其次,硬件支持的方法也是一种有效的实现临界区互斥的手段。其中,TestAndSet是一个原子指令,它用于将一个存储单元的值设置为1,并返回该存储单元旧的值。通过这个指令,我们可以实现一个简单的自旋锁。当一个进程想要进入临界区时,它会执行TestAndSet指令。如果返回值为0,则当前进程可以进入临界区;如果返回值为1,则当前进程需要等待。
最后,信号量方法是一种更高级的同步机制,它可以用来实现复杂的同步需求。信号量是一个非负整数,可以用来表示可用资源的数量。P操作用于申请资源,如果信号量的值大于0,则将其减1并进入临界区;如果信号量的值为0,则进程需要等待。V操作用于释放资源,它会将信号量的值加1,从而可能唤醒等待的进程。通过合理地设置和使用信号量,我们可以实现多个进程对临界区的互斥访问。
总的来说,实现临界区互斥的方法有多种,包括软件方法、硬件支持的方法和信号量方法。这些方法各有优缺点,适用于不同的场景和需求。在实际应用中,我们需要根据具体情况选择合适的方法来实现临界区的互斥访问。例如,在简单的系统中,我们可以使用Peterson算法或TestAndSet指令;在复杂的系统中,我们可能需要使用信号量来实现更精细的同步控制。