进程同步中 Dekker 的算法2025年1月7日 | 阅读 12 分钟 在本文中,我们将讨论进程同步中的Dekker 算法。但在讨论 Dekker 算法 之前,我们必须了解进程同步的挑战和重要性。 进程同步简介计算机系统中多个进程的同时协调称为进程同步。在讨论多进程环境(其中多个任务或进程同时运行)时,我们需要机制来共享对共享资源的访问,即内存、文件和设备。应执行进程同步以确保两个同时访问公共数据的过程不会产生冲突。 进程同步中的挑战进程同步存在一些常见挑战。其中一些如下:
进程同步的重要性操作系统运行的稳定性、可靠性和准确性都基于成功的同步。未能配备适当同步机制的系统可能会导致不可预测和不愉快的后果,例如系统崩溃、数据损坏等等。同步机制允许我们创建一个稳定有效的多进程环境。 同步: 操作系统通常是并发的,并且并行执行多个任务;因此,它们需要同步,例如共享内存,其中各种进程和任务可以与系统完整性进行交互。如果信息被多次使用或被不同的处理器使用,那么对于信息的可靠性来说,同步至关重要。 Dekker 算法简介Dekker 算法 以荷兰数学家 Thorens Veenendaal Dekker 的名字命名。该问题的经典解决方案之一是 J. Dekker。这是1968年提出的一项算法,它提供了一种在两个进程使用单一用途资源且不会遭受数据丢失和死锁的条件下进行同步的方法。 Dekker 算法很简单,但主要为双进程系统设计。该算法使用标志常量和自旋变量来同步到临界区,以便一次只有一个进程能够获得访问权限,从而限制了其他进程。通过对这些变量进行适当的调整,可以在不使用硬件支持提供的原子指令的情况下实现同步。 算法的理论方面Dekker 算法 依赖于互斥规则以及在进入临界区之前所需的基本规则。该算法通过采用以下关键组件来实现此目的:
Dekker 算法通过正确利用这些参数和条件来实现互斥,而不依赖于 T&S (Test and Set) 或 CAS (Compare and Swap) 指令。该算法的优点在于其简单性,但又在仅涉及两个进程的情况下非常有效。 与其他同步算法的比较通常将其他同步算法与 Dekker 算法进行比较,以解决临界区问题。值得注意的比较包括:
应根据这些要求、涉及的进程数量和底层硬件的特性来选择同步算法。尽管 Dekker 算法很少用于现代多核系统,但它仍然是学习进程协调概念的重要课程。 Turn 变量轮转变量 (turn variable) 对所有进程都是通用的,并标识了有权进入其临界区的进程。
标志变量 (Flag Variable)它们也被称为标志变量,指示特定进程对临界区的意图。
这些变量的作用
Dekker 算法涉及的步骤初始化:每个进程将标志初始化为 false,表示它不会向临界区移动。此外,轮转变量采用二进制值,对应于哪个进程将 first 进入临界区。 进程 A 进入临界区:进程 A 将其标志设置为TRUE,以表示其进入CS (临界区) 的意图。其次,它确保进程 B 的“标志”也已提高,因为它表明 B 也需要进入临界区。但是,如果进程 A 先执行,则轮转变量设置为 1,这意味着进程 B 将 first 进入临界区。之后,进程 A 进入一个忙等待循环,该循环包含频繁的检查以确认它是否应该访问临界区。 进程 B 进入临界区:进程 B 标记为 true,并打算进入临界区。之后,它交叉检查进程 B 的标志是否为 true,这意味着进程 B 也想进入临界区。但是,如果是这种情况,进程 B 会将轮转变量设置为零,这意味着进程 A 应该 first 进入临界区。一旦进程 B 进入其忙等待状态,它就会不断检查其进入临界区的机会。 进程 A 退出临界区:当进程 A 进入临界区时,它执行临界区的代码,并将其标志设置为 false,表示它已完成执行。此外,程序将轮转变量设置为一,这表示进程 B 可以进入临界区域。 进程 B 退出临界区:当进程 B 获得对临界区的访问权限时,它会执行临界区代码,并将自己的标志设置为 false,这意味着它已完成临界区。之后,其轮转值被设置为 0,这意味着 A 进程现在可以前往临界区。 重复:此循环根据轮转变量的值和每个进程的标志设置,交替重复这些步骤。 Python 代码让我们用 Python 代码来实现进程同步中的Dekker 算法。 代码解释CustomMutex 类
Lock 方法
Unlock 方法
critical_section 函数
thread_function 函数
示例用法
执行流程
Dekker 算法的正确性条件互斥
进度
有界等待 (Bounded Waiting)
进程速度独立性
Dekker 算法的局限性Dekker 算法的一些局限性如下:
然而,Dekker 算法专门为两个竞争进程设计。添加超过两个进程需要修改算法,这可能会导致增加复杂性。
忙等待是一种常用的算法,可以避免在使用高效调度器时可能发生的上下文切换。在循环中,它们在等待时验证当前条件并消耗 CPU,从而浪费了这些资源。
Dekker 算法中的进程通信假定使用共享内存。在缺乏共享内存的系统中,必须采用其他同步方法。
如果操作系统调度程序能够进行抢占,该算法可能会失败。 用例和示例尽管 Dekker 算法简单且仅限于两个进程,但在某些只需要简单互斥解决方案的情况下,它仍然有其狭窄但相关的应用领域。以下是一些 Dekker 算法可以应用的使用案例和场景:
在两个关键进程争夺资源的实时嵌入式系统中,Dekker 算法可以有效地避免互斥,而无需繁琐的硬件支持。
Dekker 算法长期以来一直被用作教学工具,以解释 CS 课程中进程同步的基础知识。它易于理解,适合教程目的。
如果系统仅包含两个关键竞争进程争夺同一资源,则可以有效地使用 Dekker 算法。如果更复杂的同步协议过于昂贵,则它仍然适用。
当两个进程必须同步对共享资源(如文件或打印机)的访问时,我们可以使用 Dekker 算法来防止冲突并确保有序访问。
如果整个系统规模较小,并且 Dekker 算法的简单性优于对更复杂同步机制的需求,那么它可以成为一个务实的选择(Otter,2013)。
该算法使用抢占方法,即当前进程被终止以便启动另一个进程;因此,此类系统不适合该算法,因为它们不支持进程抢占。
与其他算法相比,当两个进程以大约相同的速度运行时,Dekker 算法的性能通常很高。这意味着执行顺序与执行速度无关。 实现 Dekker 算法的挑战和考虑因素竞态条件
死锁
互斥违反
抢占问题
可扩展性问题
饥饿
缺乏普遍适用性
代码可读性和维护性
下一主题操作系统内存管理的最佳方法 |
我们请求您订阅我们的新闻通讯以获取最新更新。