Hello! Let's dive into our next topic.
In our last lesson, we compared mutex locks and spinlocks, focusing on the trade-off between blocking a process (mutex) and making it busy-wait (spinlock). We concluded that while these are effective for simple mutual exclusion, they aren't expressive enough for more complex synchronization scenarios. For instance, how do we make a process wait until a buffer is no longer empty?
This lesson introduces semaphores, a more powerful and versatile synchronization tool developed by Edsger Dijkstra. They are a cornerstone of concurrent programming and a very frequent topic in the GATE exam. Our goal is to understand the two main types—binary and counting semaphores—and learn how to apply them to solve synchronization problems.
1. What is a Semaphore?
At its core, a semaphore is simply an integer variable that is shared among threads. However, it's a special variable because it can only be accessed via two atomic operations:
wait(S)(also known asP(S)ordown(S))signal(S)(also known asV(S)orup(S))
The letters P and V come from the Dutch words Proberen (to test) and Verhogen (to increment). The atomicity of these operations is critical—it ensures that while one process is modifying the semaphore value, no other process can interfere.
There are two main types of semaphores, which we will explore in detail:
- Counting Semaphore: The integer value can range over an unrestricted domain.
- Binary Semaphore: The integer value can range only between 0 and 1.
Let's begin with a short video that introduces semaphores and these fundamental operations.
GATE 2023 Exam | CSE | Operating Systems | Semaphores (Binary & Counting) | Free Online Course
The video 'GATE 2023 Exam | CSE | Operating Systems | Semaphores (Binary & Counting)' by BYJU'S Exam Prep provides a concise introduction tailored for GATE preparation. This first segment defines what a semaphore is and explains the P (wait) and V (signal) operations.
Watch from 01:55 to 04:24. Focus on the definition of a semaphore and the function of the wait (decrement) and signal (increment) operations.
To see the standard implementation of these operations, you can review the following document. It provides the pseudocode that forms the basis of how semaphores work.
The document 'Operating Systems' from Vidyalankar provides the formal structure and algorithms for semaphore operations.
Read the first page of the 'SEMAPHORES' section (page 35 in the PDF). Pay attention to the struct semaphore definition and the pseudocode for the wait(semaphore s) and signal(semaphore s) functions. This gives you the 'under-the-hood' view.
2. Counting Semaphores
A counting semaphore is used to control access to a resource that has multiple instances—for example, a pool of database connections or a fixed number of identical printers.
- Initialization: The semaphore is initialized to the number of available resources, let's say
k. wait()Operation: When a process wants to use a resource, it executeswait(S). This decrements the semaphore count (S--).- If the resulting value of
Sis non-negative (S >= 0), the process continues, having successfully acquired a resource. - If the resulting value of
Sis negative (S < 0), it means no resources were available. The process is blocked and placed in a waiting queue associated with the semaphore.
- If the resulting value of
signal()Operation: When a process releases a resource, it executessignal(S). This increments the semaphore count (S++).- If the value of
Safter incrementing is less than or equal to 0 (S <= 0), it means there are processes waiting for this resource. The operating system will wake up one of the blocked processes from the queue.
- If the value of
A Key Insight for GATE
The value of a counting semaphore tells you about the state of the system:
- If
S > 0, there areSresources available. - If
S = 0, all resources are currently in use, but no processes are waiting. - If
S < 0, all resources are in use, and|S|(the absolute value of S) processes are blocked in the waiting queue.
This last point is a frequent source of GATE questions. For example, if a semaphore's value is -3, you know that 3 processes are currently blocked waiting for that resource.
Let's see this in action with an example.
GATE 2023 Exam | CSE | Operating Systems | Semaphores (Binary & Counting) | Free Online Course
The same video from BYJU's now provides a clear walkthrough of a counting semaphore example. It shows how the semaphore value changes as processes acquire and release resources.
Watch from 04:24 to 09:35. Follow the example with processes P1, P2, and P3, and observe how the semaphore value becomes negative when a process has to block.
3. Binary Semaphores
A binary semaphore is a simpler version, restricted to the values 0 and 1. It functions essentially as a mutex lock, which we discussed in the previous lesson.
- Initialization: For mutual exclusion, a binary semaphore is initialized to
1, indicating that the critical section is initially available. wait()Operation: A process callswait(S)before entering the critical section. IfSis 1, it is decremented to 0, and the process enters. IfSis already 0, the process blocks until the semaphore is released.signal()Operation: After leaving the critical section, the process callssignal(S). This setsSback to 1 and wakes up a waiting process, if any.
Binary semaphores are used to enforce mutual exclusion for a single resource.
GATE 2023 Exam | CSE | Operating Systems | Semaphores (Binary & Counting) | Free Online Course
This next segment from the BYJU's video explains binary semaphores and their role in providing mutual exclusion.
Watch from 09:35 to 14:09. Note how the logic ensures that only one process can be in the critical section at a time, making it behave like a mutex.
Test your understanding!
A system has 8 identical, sharable resources. A counting semaphore S is used to manage them.
- What should the initial value of
Sbe? - What is the value of
Safter 5 processes have each taken one resource? - What is the value of
Safter 10 processes have each requested one resource? How many processes are blocked?
Show answer
- The initial value of
Sshould be 8. - After 5
wait()operations, the value ofSwill be8 - 5 = 3. - After 10
wait()operations, the value ofSwill be8 - 10 = -2. This means 2 processes are blocked in the waiting queue.
4. Solving GATE Problems with Semaphores
For the GATE exam, you'll often see questions that require you to calculate the final value of a semaphore or determine system state based on a sequence of P and V operations.
Problem Type 1: Final Value Calculation
This is the most straightforward type of problem. Remember:
- Each
Poperation decrements the value. - Each
Voperation increments the value.
Example 1: A counting semaphore S is initialized to 7. In a certain period, 20 P operations and 15 V operations are performed. What is the final value of S?
- Calculation:
Initial Value - (Number of P ops) + (Number of V ops) 7 - 20 + 15 = -13 + 15 = 2- The final value is 2.
Example 2 (Slightly trickier): During an execution, 20 P operations and 12 V operations were issued in some order on a counting semaphore S. What is the largest initial value of S for which at least one P operation will remain blocked?
- Logic: For a process to be blocked, the semaphore value must become negative. For at least one process to be blocked, the final value of the semaphore must be -1. (If it were -2, two processes would be blocked, etc.)
- Let the initial value be
S_initial. - Equation:
S_initial - 20 + 12 = -1 S_initial - 8 = -1S_initial = 7- The largest initial value is 7.
Now, watch the video instructor solve these exact problems.
GATE 2023 Exam | CSE | Operating Systems | Semaphores (Binary & Counting) | Free Online Course
This segment of the BYJU's video walks through solutions to several GATE previous year questions involving semaphore value calculations. This will solidify your understanding of the mechanics.
Watch from 14:09 to 20:27. This covers the two examples above and one more, reinforcing the problem-solving technique.
Problem Type 2: Race Conditions with Semaphores
More complex questions involve analyzing code snippets to find possible outcomes, especially when semaphores are used to control access to a shared variable. A counting semaphore initialized to a value greater than 1 does not guarantee mutual exclusion, which can lead to race conditions.
Test your understanding! (GATE 2023 Problem)
Consider two functions, incr and decr, that use a semaphore s to access a shared variable X.
// Shared variable
int X;
// Semaphore
semaphore s;
void incr() {
wait(s);
X = X + 1;
signal(s);
}
void decr() {
wait(s);
X = X - 1;
signal(s);
}
There are 5 threads each invoking incr once, and 3 threads each invoking decr once. The initial value of X is 10. The operations X = X + 1 and X = X - 1 are not atomic.
Consider two implementations:
- I-1:
sis a binary semaphore initialized to 1. - I-2:
sis a counting semaphore initialized to 2.
Let V1 and V2 be the minimum possible values of X at the end of execution for I-1 and I-2, respectively. What are V1 and V2?
Show answer
Case I-1: Binary Semaphore (s = 1)
- A binary semaphore initialized to 1 acts as a mutex. It guarantees mutual exclusion.
- This means only one thread can be inside the critical section (
X = X + 1orX = X - 1) at any time. - Therefore, the operations on
Xare effectively serialized. The final result is deterministic, regardless of the order of execution. - Final Value:
10 + (5 increments) - (3 decrements) = 10 + 5 - 3 = 12. - So, V1 = 12.
Case I-2: Counting Semaphore (s = 2)
- A counting semaphore initialized to 2 allows up to two threads to be in the critical section simultaneously. This breaks mutual exclusion and allows for race conditions.
- We want to find the minimum possible value of
X. This happens when decrements have the maximum impact and increments are "lost". - The
X = X op 1operation is a three-step process: (1) Read X into a register, (2) Perform operation in the register, (3) Write register value back to X. - Here is a scenario for the minimum value:
- An
incrthread (let's call itT_inc1) enters. It executeswait(s), sosbecomes 1. It readsX(value 10) into its register. It gets preempted. - A
decrthread (T_dec1) enters. It executeswait(s), sosbecomes 0. It readsX(value 10) into its register. It also gets preempted. - Now,
sis 0, so no more threads can enter. - Let all 4 remaining
incrthreads run to completion one by one. Each will wait, execute, and signal. The final value ofXwill be10 + 4 = 14. - Now, the original
T_inc1resumes. Its register still holds 10. It calculates10 + 1 = 11and writes11back toX. The work of the other 4incrthreads is lost!Xis now 11.T_inc1signals, sosbecomes 1. - Now, the original
T_dec1resumes. Its register still holds 10. It calculates10 - 1 = 9and writes9back toX. The work of all 5incrthreads is lost!Xis now 9.T_dec1signals, sosbecomes 2. - Finally, the remaining 2
decrthreads run sequentially, decrementingXfrom 9 to 8, and then to 7.
- An
- The minimum possible value is 7.
- So, V2 = 7.
The correct answer is V1=12, V2=7. You can find a detailed discussion of this exact problem on the Gate Overflow page for GATE CSE 2023, Question 28.
Conclusion
Today we introduced semaphores, a versatile tool that overcomes the limitations of simple mutex locks. We have seen how they can be used to manage a pool of resources or to ensure simple mutual exclusion.
Key Takeaways:
- Semaphores are integer variables accessed only through atomic
wait(P)andsignal(V)operations. - Counting semaphores can have any non-negative integer value and are ideal for managing a pool of
kidentical resources. A negative value-nindicates thatnprocesses are blocked. - Binary semaphores are restricted to 0 and 1 and are used for mutual exclusion, making them functionally equivalent to mutex locks.
- Understanding the non-atomic nature of high-level programming statements (like
x = x + 1) is key to solving complex GATE problems involving race conditions.
So far, we've used semaphores for basic resource counting and mutual exclusion. In our next lesson, we will apply them to solve a classic and important synchronization challenge: the Producer-Consumer Problem. This will showcase the true power of semaphores for coordinating complex process interactions.