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
    🧩
    Parallel & Distributed Computing
    COMP3139
    Progress0 / 33 topics
    Topics
    1. Introduction to Parallel and Distributed Systems2. Why Use Parallel and Distributed Systems?3. Speedup and Amdahl's Law4. Hardware Architectures: Multi Processors (Shared Memory)5. Hardware Architectures: Networks of Workstations (Distributed Memory)6. Hardware Architectures: Clusters (Latest Variation)7. Software Architectures: Threads and Shared Memory8. Software Architectures: Processes and Message Passing9. Software Architectures: Distributed Shared Memory (DSM)10. Software Architectures: Distributed Shared Data (DSD)11. Parallel Algorithms12. Concurrency and Synchronization13. Data and Work Partitioning14. Common Parallelization Strategies15. Granularity16. Load Balancing17. Examples of Parallel Algorithms: Parallel Search18. Examples of Parallel Algorithms: Parallel Sorting19. Shared-Memory Programming20. Threads in Shared-Memory Programming21. P Threads22. Locks and Semaphores23. Distributed-Memory Programming24. Message Passing25. Map Reduce26. Distributed-Memory Programming with PI27. Google's Map Reduce28. Hadoop29. Other Parallel Programming Systems30. Tread Marks31. Distributed Shared Memory32. Aurora: Scoped Behavior and Abstract Data Types33. S Enterprise: Process Templates
    COMP3139›Locks and Semaphores
    Parallel & Distributed ComputingTopic 22 of 33

    Locks and Semaphores

    7 minread
    1,203words
    Intermediatelevel

    Locks and Semaphores

    Locks and semaphores are two of the most commonly used synchronization primitives in parallel and concurrent programming. Both are used to manage access to shared resources, preventing race conditions, ensuring mutual exclusion, and allowing synchronization between threads or processes. While they are conceptually similar, they are used in slightly different ways and offer different levels of control.

    Let’s break down locks and semaphores, understand their differences, and explore their usage in programming.


    1. Locks (Mutexes)

    A lock is a synchronization mechanism used to enforce mutual exclusion (mutex) by ensuring that only one thread or process can access a critical section of code at a time. When a thread locks a resource, no other thread can access it until the lock is released.

    Key Points about Locks:

    • Mutual Exclusion: Locks provide mutual exclusion, meaning only one thread can execute a critical section at any given time.
    • Blocking: If a thread tries to acquire a lock that is already held by another thread, it will block (wait) until the lock is released.
    • Unlocking: Once a thread finishes executing the critical section, it releases the lock, allowing other threads to acquire it.

    Common Operations for Locks:

    • lock: A thread locks a mutex or a lock, blocking if it’s already locked.
    • unlock: A thread releases a lock, allowing other threads to acquire it.

    Types of Locks:

    • Mutex (Mutual Exclusion Lock): A type of lock that can only be acquired by one thread at a time.
    • Reentrant Mutex: A type of mutex that allows the same thread to lock the mutex multiple times without causing deadlock.
    • Spinlock: A lock where a thread repeatedly checks (spins) to see if the lock is available. It is typically used when the lock is expected to be held for a very short period of time.

    Example (C using PThreads):

    #include <pthread.h>
    #include <stdio.h>
    
    pthread_mutex_t lock;  // Declare a mutex
    
    void* thread_func(void* arg) {
        pthread_mutex_lock(&lock);  // Acquire the lock
        printf("Thread is executing critical section\n");
        pthread_mutex_unlock(&lock);  // Release the lock
        return NULL;
    }
    
    int main() {
        pthread_t thread1, thread2;
        pthread_mutex_init(&lock, NULL);  // Initialize the mutex
    
        // Create two threads
        pthread_create(&thread1, NULL, thread_func, NULL);
        pthread_create(&thread2, NULL, thread_func, NULL);
    
        // Wait for both threads to finish
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);
    
        pthread_mutex_destroy(&lock);  // Clean up the mutex
        return 0;
    }
    

    In this example, the mutex ensures that only one thread at a time can enter the critical section where the shared resource is being accessed.


    2. Semaphores

    A semaphore is another synchronization primitive, but it is more general than a lock. It is essentially a counter that controls access to resources. Semaphores can be used for both mutual exclusion and synchronization between threads or processes.

    A semaphore is initialized with an integer value, and operations on a semaphore involve incrementing or decrementing that value. Semaphores are typically used to signal one or more threads that they can proceed with a certain task or to limit the number of threads that can access a specific resource.

    Types of Semaphores:

    • Binary Semaphore (Mutex): A special case of a semaphore where the counter can only take two values: 0 or 1. It is used to implement mutual exclusion (like a lock).
    • Counting Semaphore: A semaphore where the counter can take any non-negative integer value. It is used to limit access to a pool of resources (e.g., database connections, threads).

    Operations on Semaphores:

    • wait (P operation): Decreases the semaphore’s counter. If the counter is already zero, the calling thread will block until the counter becomes positive.
    • signal (V operation): Increases the semaphore’s counter. If there are threads waiting, one of them may be unblocked.

    The names P and V come from the Dutch words "proberen" (to test) and "verhogen" (to increment), and are used in some academic contexts.

    Example (C using PThreads with a Counting Semaphore):

    #include <pthread.h>
    #include <stdio.h>
    #include <semaphore.h>
    
    sem_t semaphore;  // Declare a semaphore
    
    void* thread_func(void* arg) {
        sem_wait(&semaphore);  // Decrement semaphore and block if it's 0
        printf("Thread is executing critical section\n");
        sem_post(&semaphore);  // Increment semaphore (release)
        return NULL;
    }
    
    int main() {
        pthread_t thread1, thread2;
    
        sem_init(&semaphore, 0, 1);  // Initialize semaphore (binary, value 1)
    
        // Create two threads
        pthread_create(&thread1, NULL, thread_func, NULL);
        pthread_create(&thread2, NULL, thread_func, NULL);
    
        // Wait for both threads to finish
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);
    
        sem_destroy(&semaphore);  // Clean up the semaphore
        return 0;
    }
    

    In this example, the semaphore is used to control access to the critical section. If one thread holds the semaphore (decrements the count), the other thread will block until the first thread releases the semaphore by incrementing the count.


    3. Differences Between Locks and Semaphores

    While both locks and semaphores are used to manage synchronization, they differ in functionality and use cases.

    Feature Locks (Mutexes) Semaphores
    Purpose Provide mutual exclusion for critical sections of code Control access to shared resources and synchronize threads
    Type of Resource Binary (locked/unlocked) Can be binary (mutex) or counting (multiple resources)
    Value Can only be locked (1) or unlocked (0) Can hold any integer value (typically ≥ 0)
    Operations lock(), unlock() wait(), signal()
    Blocking A thread blocks until the lock is released A thread blocks if the semaphore count is 0 (for counting semaphores)
    Typical Use Protecting a single resource or critical section Managing access to a pool of resources (e.g., limiting the number of threads accessing a resource)
    Counting Ability No counting mechanism (binary state) Can count (e.g., counting semaphores)

    When to Use Locks:

    • When you need exclusive access to a single shared resource.
    • When only one thread should be allowed to enter a critical section at any given time (e.g., updating a shared variable).

    When to Use Semaphores:

    • When you need to manage access to a pool of resources or control the concurrency level (e.g., limiting the number of threads that can access a database).
    • When you need to synchronize threads, ensuring they wait for a certain condition before proceeding.

    4. Advantages and Disadvantages

    Locks:

    • Advantages:
      • Simpler to use for protecting individual critical sections.
      • Prevents multiple threads from entering a critical section simultaneously.
    • Disadvantages:
      • If not used properly, can lead to deadlock (if threads acquire multiple locks in different orders).
      • No direct support for managing multiple shared resources or concurrency levels.

    Semaphores:

    • Advantages:
      • Can manage access to multiple resources or a pool of resources (e.g., limiting the number of threads accessing a resource).
      • More flexible than locks for certain types of synchronization.
    • Disadvantages:
      • Slightly more complex to use correctly compared to simple locks.
      • The counter value must be managed carefully to avoid inconsistencies.

    5. Conclusion

    Locks and semaphores are essential tools for synchronization in concurrent programming. While locks are best suited for mutual exclusion, where only one thread should access a resource at a time, semaphores provide more general mechanisms for managing resources and synchronizing threads in more complex scenarios. Understanding when and how to use these tools is critical for developing correct, efficient, and scalable parallel programs.

    Previous topic 21
    P Threads
    Next topic 23
    Distributed-Memory Programming

    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,203
      Code examples0
      DifficultyIntermediate