Dekker's Algorithm in Process Synchronization


Introduction

Process synchronization is a critical concept in computer science, especially in operating systems. It involves coordinating the activities of multiple processes to ensure that they run correctly and avoid conflicts. Mutual exclusion is a fundamental problem in process synchronization that arises when multiple processes need to access a shared resource or critical section. If two or more processes simultaneously access the same shared resource, it can lead to incorrect results or data corruption.

To solve this problem, various algorithms have been developed over the years. One of the most popular of these is Dekker's algorithm, which was proposed by Cornelis Dekker in 1965. It is a simple and efficient algorithm that allows only one process to access a shared resource at a time. The algorithm achieves mutual exclusion by using two flags that indicate each process's intent to enter the critical section. By alternating the flags' use and checking if the other process's flag is set, the algorithm ensures that only one process enters the critical section at a time.

Algorithm

The algorithm uses flags to indicate the intention of each process to enter a critical section, and a turn variable to determine which process is allowed to enter the critical section first.

Here are the detailed steps involved in Dekker's Algorithm −

  • Initialization − Each process sets its flag to false initially, indicating that it does not intend to enter the critical section. The turn variable is also set to the value of either 0 or 1, indicating which process is allowed to enter the critical section first.

  • Process A enters the critical section − Process A sets its flag to true, indicating its intention to enter the critical section. It then checks if Process B's flag is also true, indicating that Process B also wants to enter the critical section. If so, Process A sets the turn variable to 1, indicating that it is Process B's turn to enter the critical section first. Process A then enters a busy-wait loop, repeatedly checking if it is its turn to enter the critical section.

  • Process B enters the critical section − Process B sets its flag to true, indicating its intention to enter the critical section. It then checks if Process A's flag is also true, indicating that Process A also wants to enter the critical section. If so, Process B sets the turn variable to 0, indicating that it is Process A's turn to enter the critical section first. Process B then enters a busy-wait loop, repeatedly checking if it is its turn to enter the critical section.

  • Process A exits the critical section − Once Process A is allowed to enter the critical section, it executes the critical section code and then sets its flag to false, indicating that it is done with the critical section. It then sets the turn variable to 1, indicating that it is now Process B's turn to enter the critical section.

  • Process B exits the critical section − Once Process B is allowed to enter the critical section, it executes the critical section code and then sets its flag to false, indicating that it is done with the critical section. It then sets the turn variable to 0, indicating that it is now Process A's turn to enter the critical section.

  • Repeat − The two processes then repeat the above steps, alternating between entering and exiting the critical section as determined by the turn variable and the state of each process's flag.

Use cases

Dekker's Algorithm can be applied in various systems and platforms that require mutual exclusion.

Here are some examples −

  • Operating systems − Dekker's Algorithm can be used in operating systems to prevent multiple processes from accessing a shared resource simultaneously. For example, if two processes need to access a file, Dekker's Algorithm can be used to ensure that only one process accesses the file at any given time.

  • Robotics − In robotics, multiple processes may need to control the movement of a robot. Dekker's Algorithm can be used to ensure that only one process controls the robot's movement at any given time, preventing collisions or other issues.

  • Web servers − In web servers, multiple threads may need to access a shared resource, such as a database or file. Dekker's Algorithm can be used to ensure that only one thread accesses the resource at any given time, preventing race conditions or data corruption.

  • Real-time Systems − In real-time systems, timing constraints are critical, and processes need to execute within a specific deadline. Dekker's Algorithm can be used to ensure that only one process at a time can access a critical section of code that affects the system's timing behavior. This can prevent timing violations, priority inversion, and other real-time synchronization problems.

  • Embedded Systems − In embedded systems, resources such as memory, peripherals, and sensors are often shared among multiple processes or threads. Dekker's Algorithm can be used to ensure that only one process at a time can access a critical section of code that modifies or accesses a shared resource. This can prevent data corruption, race conditions, and other synchronization problems that can compromise the system's reliability and safety.

Dekker's Algorithm can be implemented in code using any programming language

Here is an example implementation of Dekker's Algorithm in Python −

import threading
class Dekker:
   def __init__(self):
      self.flag = [False, False]
      self.turn = 0

def lock(self, i):
   self.flag[i] = True
   while self.flag[1-i]:
      if self.turn == 1-i:
         self.flag[i] = False
         while self.turn == 1-i:
            pass
         self.flag[i] = True
      self.turn = 1-i

def unlock(self, i):
   self.flag[i] = False

# Sample usage
dekker = Dekker()

def critical_section(thread_num):
   print("Thread", thread_num, "entered critical section")
   # Perform critical section operations here
   print("Thread", thread_num, "exited critical section")
   dekker.unlock(thread_num)

def thread_function(thread_num):
   dekker.lock(thread_num)
   critical_section(thread_num)

# Create two threads
   thread_1 = threading.Thread(target=thread_function, args=(0,))
   thread_2 = threading.Thread(target=thread_function, args=(1,))

# Start the threads
thread_1.start()
thread_2.start()

# Wait for the threads to finish
thread_1.join()
thread_2.join()

In this implementation, the Dekker class contains the shared variables flag and turn, which represent the state of the algorithm. The lock and unlock methods implement the entry and exit phases of the algorithm, respectively.

The thread_function function represents the code executed by each thread, which first acquires the lock using the lock method and then enters the critical section to perform operations. Once the thread has finished its critical section, it releases the lock using the unlock method.

This implementation uses Python's built-in threading module to create and manage the threads. The start method is used to start each thread, and the join method is used to wait for the threads to finish.

Strengths and Weaknesses of the algorithm

Strengths

  • Dekker's Algorithm is simple and easy to understand.

  • The algorithm guarantees mutual exclusion and progress, meaning that at least one process will eventually enter the critical section.

  • The algorithm does not require hardware support and can be implemented in software.

Weaknesses

  • The algorithm is prone to starvation since it does not ensure fairness, meaning that one process could continuously enter the critical section while the other process waits indefinitely.

  • The algorithm requires busy waiting, which can lead to high CPU usage and inefficiency.

  • The algorithm is susceptible to race conditions and may fail under certain conditions.

Time complexity

  • The time complexity of the algorithm is O(n^2) in the worst case, where n is the number of processes.

  • This is because each process may need to wait for the other process to finish its critical section, leading to a potential infinite loop.

Space complexity

  • The space complexity of the algorithm is O(1), as it only requires a few flags and turn variables.

Comparison with other mutual exclusion algorithms

  • Peterson's Algorithm is another classic mutual exclusion algorithm that is similar to Dekker's Algorithm. Peterson's Algorithm also uses flags and turn variables, but it avoids busy waiting by using turn variables to determine which process should go first. Peterson's Algorithm is fairer than Dekker's Algorithm but may require hardware support in some cases.

  • Bakery Algorithm is another mutual exclusion algorithm that is more complex than Dekker's Algorithm. It avoids busy waiting and starvation by assigning each process a number and comparing the numbers to determine which process should enter the critical section first. The Bakery Algorithm is fair and efficient but may require more memory than Dekker's Algorithm.

Conclusion

Dekker's Algorithm is a classic algorithm for solving the mutual exclusion problem in process synchronization. It provides a simple and effective software-based solution for two processes to share a critical section of code without interfering with each other.Although the algorithm has some limitations, such as its scalability and potential wastage of CPU time, it remains a popular choice for teaching the basics of concurrency and synchronization in computer science courses. Dekker's Algorithm has also inspired the development of other algorithms and techniques that address the mutual exclusion problem in more complex scenarios.

Updated on: 04-Apr-2023

2K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements