ScholarQuill logoScholarQuillUniversity Notes
  • Notes
  • Past Papers
  • Blogs
  • Todo
Login
ScholarQuill logoScholarQuillUniversity Notes
Login
NotesPast PapersBlogsTodo
More
SubjectsDiscussionCGPA CalculatorGPA CalculatorStudent PortalCourse Outline
About
About usPrivacy PolicyReportContact
Notes
Past Papers
Blogs
Todo
Analytics
    Current Subject
    🧩
    Operating Systems
    CC-211
    Progress0 / 34 topics
    Topics
    1. Operating Systems Basics2. System Calls3. Process Concept and Scheduling4. Interprocess Communication5. Multithreaded Programming6. Multithreading Models7. Threading Issues8. Process Scheduling Algorithms9. Thread Scheduling10. Multiple-Processor Scheduling11. Synchronization12. Critical Section13. Synchronization Hardware14. Synchronization Problems15. Deadlocks16. Detecting and Recovering from Deadlocks17. Memory Management18. Swapping19. Contiguous Memory Allocation20. Segmentation and Paging21. Virtual Memory Management22. Demand Paging23. Thrashing24. Memory-Mapped Files25. File Systems26. File Concept27. Directory and Disk Structure28. Directory Implementation29. Free Space Management30. Disk Structure and Scheduling31. Swap Space Management32. System Protection33. Virtual Machines34. Operating System Security
    CC-311›Critical Section
    Operating SystemsTopic 12 of 34

    Critical Section

    7 minread
    1,180words
    Intermediatelevel

    Critical Section in Operating Systems

    A critical section is a part of a program where shared resources (such as data structures, files, or devices) are accessed and modified by multiple threads or processes. Since these resources are shared, there is a risk that concurrent access can lead to race conditions, data corruption, and inconsistent behavior. To prevent such issues, only one thread or process should be allowed to execute in the critical section at any given time.

    Key Concepts Related to Critical Sections

    1. Mutual Exclusion (Mutex):

      • Mutual exclusion ensures that if one thread is executing in a critical section, no other thread can enter that critical section until the first thread exits. This is the core principle of protecting critical sections.
      • Mutual exclusion is achieved through synchronization mechanisms like locks, mutexes, and semaphores, which prevent multiple threads from concurrently modifying shared resources.
    2. Race Condition:

      • A race condition occurs when multiple threads or processes access and modify shared data concurrently, and the final result depends on the order of execution. This can lead to unpredictable behavior and errors.
      • The critical section concept is designed to prevent race conditions by ensuring that only one thread can access the critical section at a time.
    3. Shared Resources:

      • A shared resource is any resource that can be used by multiple threads or processes. Examples include variables, files, databases, or hardware devices.
      • The critical section is specifically used to protect shared resources from being accessed concurrently by multiple threads.

    Problem with Critical Sections

    The main problem with critical sections is how to ensure that only one thread or process is in the critical section at any given time, while others are blocked or delayed until it is safe for them to enter.

    If multiple threads are allowed to access the critical section concurrently, it can lead to:

    • Inconsistent data: If multiple threads modify shared data simultaneously, it can lead to unpredictable results.
    • Race conditions: The outcome of operations can depend on the timing of thread execution, which is typically non-deterministic.
    • Data corruption: Incorrect data may be written to memory or files if two threads try to write to the same memory location at the same time.

    To address these issues, we use synchronization mechanisms that enforce mutual exclusion.


    Solutions to Protect Critical Sections

    The primary solution to ensure mutual exclusion in critical sections is the use of synchronization mechanisms. Several methods are commonly used in operating systems:

    1. Locks (Mutexes):

    • A lock (or mutex) ensures that only one thread can enter the critical section at a time. When a thread enters the critical section, it locks the resource, preventing other threads from accessing it.
    • Lock acquisition and release:
      • A thread must acquire the lock before entering the critical section.
      • Once done, the thread releases the lock so that other threads can acquire it.
    • Example:
      lock = threading.Lock()
      
      def critical_section():
          lock.acquire()  # Enter critical section
          # Perform operations on shared resources
          lock.release()  # Exit critical section
      

    2. Semaphores:

    • A semaphore is a more general synchronization tool used for controlling access to shared resources. It uses a counter to track how many threads can access the critical section.
    • A binary semaphore (also known as a mutex) has only two values (0 or 1) and is typically used to implement mutual exclusion.
    • Operations on semaphores include:
      • Wait (P): Decrements the semaphore value and blocks if the value is 0.
      • Signal (V): Increments the semaphore value and may unblock waiting threads.
    • Example:
      semaphore = threading.Semaphore(1)  # Binary semaphore, only one thread can access
      
      def critical_section():
          semaphore.acquire()  # Enter critical section
          # Perform operations on shared resources
          semaphore.release()  # Exit critical section
      

    3. Monitors:

    • A monitor is a higher-level abstraction that combines mutual exclusion with the ability to wait for certain conditions to be met. A monitor is a synchronization construct that encapsulates shared data and the procedures that operate on it.
    • A monitor allows only one thread to execute within it at any time, and it uses condition variables to manage the waiting and signaling of threads.
    • Example in Python (using threading.Condition):
      condition = threading.Condition()
      
      def critical_section():
          with condition:
              # Perform operations on shared resources
              condition.wait()  # Thread can wait on the condition
              condition.notify()  # Notify other waiting threads
      

    4. Atomic Operations:

    • Atomic operations are indivisible operations that are performed without interruption. They prevent race conditions by ensuring that a critical section cannot be interrupted while it is executing.
    • For example, an atomic increment operation on a shared variable would ensure that the variable is updated correctly, even if multiple threads are attempting to increment it concurrently.
    • Many programming languages provide atomic operations, like atomic add, compare-and-swap (CAS), etc.

    Requirements for a Critical Section Solution

    To ensure that a solution for critical sections is effective and prevents issues like race conditions, the solution must satisfy the following conditions:

    1. Mutual Exclusion:

      • Only one thread can be in the critical section at a time.
    2. Progress:

      • If no thread is in the critical section, and one or more threads want to enter, one of them should eventually be allowed to do so.
    3. Bounded Waiting:

      • A thread that wants to enter the critical section should not be denied access indefinitely. There must be a limit on how many times other threads can enter before the waiting thread is allowed to enter.

    Examples of Critical Section Problems

    1. Producer-Consumer Problem:

      • This classic synchronization problem involves two types of processes: producers and consumers. Producers generate data and place it into a shared buffer, while consumers take data from the buffer.
      • The critical section in this problem involves accessing the shared buffer, where the producer and consumer must not simultaneously access the buffer to avoid corruption or inconsistency.
    2. Reader-Writer Problem:

      • In this problem, a set of readers can simultaneously access shared data for reading, but if there is a writer, no other thread (reader or writer) can access the data. The goal is to allow readers to access the data concurrently while ensuring that writers have exclusive access.
      • The critical section here involves managing the access to the shared data and ensuring that writers do not conflict with readers.
    3. Bank Account Example:

      • Consider a situation where multiple threads are trying to deposit or withdraw money from a bank account. The critical section in this case would be the part where the balance is updated, as multiple threads attempting to update the balance at the same time could cause inconsistencies.

    Conclusion

    The critical section is a key concept in concurrent programming, particularly in multi-threaded and multi-process systems, as it represents the shared portion of the program where synchronization must be carefully managed to prevent race conditions, data corruption, and other issues. By using synchronization techniques like locks, semaphores, monitors, and atomic operations, operating systems ensure that only one thread or process can access shared resources at any given time, providing safe and predictable behavior in concurrent systems. Proper management of critical sections is crucial for writing efficient, correct, and stable programs in modern operating systems.

    Previous topic 11
    Synchronization
    Next topic 13
    Synchronization Hardware

    Past Papers

    Open this section to load past papers

    Click on Show Past Papers to see past papers.
    On This Page
      Reading Stats
      Est. reading time7 min
      Word count1,180
      Code examples0
      DifficultyIntermediate