Semaphores for Ordering

 

Semaphores for Ordering

So far, we have seen how semaphores can be used as locks (binary semaphores) to protect critical sections.
However, semaphores are more general than locks. Another very important use is ordering events in concurrent programs.


What Does “Ordering” Mean?

In concurrency, ordering means:

Ensuring that one thread performs an action only after another thread has completed some event.

This is different from mutual exclusion:

  • Locks → prevent simultaneous access

  • Ordering semaphores → enforce “this must happen before that”

This usage is similar in spirit to condition variables, but semaphores can do both jobs.


Parent–Child Example 

Consider a simple program:

  • The parent thread creates a child thread

  • The parent must wait until the child finishes

  • Desired output order:

    parent: begin child parent: end

Code Using a Semaphore

sem_t s; void *child(void *arg) { printf("child\n"); sem_post(&s); // signal that child is done return NULL; } int main() { sem_init(&s, 0, 0); // initialize semaphore to 0 printf("parent: begin\n"); pthread_t c; pthread_create(&c, NULL, child, NULL); sem_wait(&s); // wait for child printf("parent: end\n"); return 0; }

Key Question: Why Is the Initial Value 0?

The semaphore represents an event:

“The child has finished executing”

  • Before the child finishes → event has not happened

  • After the child finishes → event has happened

Thus:

  • Initial value must be 0

  • sem_post() signals the event

  • sem_wait() waits for the event


Case 1: Parent Waits Before Child Runs (Figure 31.7)

Situation

  • Parent creates child

  • Parent reaches sem_wait() before child runs

What Happens?

Semaphore ValueParent StateChild StateExplanation
0RunReadySemaphore initialized
0call sem_wait()ReadyParent tries to wait
-1Run → SleepReadySemaphore < 0 → parent blocks
-1SleepRunChild now runs
-1Sleepcall sem_post()Child signals completion
0SleepRunSemaphore incremented
0ReadyRunParent is awakened
0RunReadyParent resumes
0sem_wait() returnsReadyOrdering achieved

Result

  • Parent waits correctly

  • Child prints first

  • Parent resumes afterward





Case 2: Child Runs Before Parent Waits (Figure 31.8)

Situation

  • Child runs immediately

  • Parent hasn’t reached sem_wait() yet

What Happens?

Semaphore ValueParent StateChild StateExplanation
0RunReadySemaphore initialized
0ReadyRunChild scheduled first
0Readycall sem_post()Child signals completion
1ReadyRunSemaphore incremented
1RunReadyParent now runs
1call sem_wait()ReadyParent waits
0RunReadyNo blocking; semaphore ≥ 0
0sem_wait() returnsReadyParent continues

Result

  • Parent does not block

  • Semaphore “remembers” the signal

  • Correct ordering still achieved




Why Semaphores Work for Ordering

Semaphores work for ordering because:

  1. They remember signals

    • If sem_post() happens first, the value increases

  2. They block when necessary

    • If sem_wait() happens first, the thread sleeps

  3. No lost wakeups

    • Unlike naive signaling, semaphores store state

This is why semaphores are often described as:

“A counter + a queue of waiting threads”


Comparison: Locks vs Ordering Semaphores

AspectLockOrdering Semaphore
Purpose        Mutual exclusion        Event ordering
Initial value            1            0
Blocks when        Lock held        Event not occurred
Typical usage        Critical section        Parent–child, producer–consumer

 Summary

  • Semaphores can be used not only as locks, but also to order events

  • Initialize semaphore to 0 for ordering

  • sem_wait() waits for an event

  • sem_post() signals an event

  • Works correctly regardless of thread scheduling order

  • Figures 31.7 and 31.8 show that both execution orders are handled safely

Comments

Popular posts from this blog

Operating Systems OS PCCST403 Semester 4 BTech KTU CS 2024 Scheme

Introduction to Operating System -Virtualization, Concurrency, and Persistence

Differences Between Linux and Classic UNIX Kernels