You are on page 1of 54

Real-Time Concepts for

Embedded Systems
Author: Qing Li with
Caroline Yao
ISBN: 1-57820-124-1
CMPBooks

Chapter 6
Semaphores

Outline

6.1 Introduction
6.2 Defining a Semaphores
6.3 Typical Semaphore Operations
6.4 Typical Semaphore Use

6.1 Introduction

Multiple concurrent threads of execution


within an application must be able to

Synchronize their execution


Coordinate mutually exclusive access to shared
resources

RTOS provides a semaphore object and


associated semaphore management services

Problem Without Synchronization

A main program creates four identical threads

Each thread increments the same global variable


250,000 times
Thus, a count is incremented a total of 1,000,000
times
The main program waits for the four threads to
complete and print out the global count variable.

Program Listing
volatile INT count;
void CountThread( INT iterations)
{
INT i;
INT x;
for (i = 0; i < iterations; i++) {
x = count;
x++;
count = x;
}

Program Listing (Cont.)


void main(void)
{
for ( i = 0; i<numThreads; i++) {
handles[i] = CreateThread (CountThread, &threadID);
}
WaitForMultipleObjects();
printf(Global count = %d\n, count);
}

Execution Results

Global Count = 469459


Global Count = 520484
Global Count = 459216
Global Count = 508529
Global Count = 710670
However, the correct value should be
1,000,000

6.2 Defining Semaphores

A semaphore or semaphore token

A kernel object that one or more threads of execution can


acquire or release for the purpose of synchronization or
mutual exclusion

When a semaphore is first created, kernel assign

An semaphore control block (SCB)


A unique ID
A value (binary or a count)
A task-waiting list

A Semaphore, its Associated Parameters,


and Supporting Data Structures

Semaphore

A key that allows a task to carry out some


operation or to access a resource

A single semaphore can be acquired a finite


number of times
Acquire a semaphore is like acquiring the
duplicate of a key
If the token counter reach 0

The semaphore has no token left


A requesting task cannot acquire the semaphore and
may block if it chooses to wait

Semaphore (Cont.)

Task-waiting list track of all tasks blocked


while waiting on an unavailable semaphore

FIFO: first-in-first-out order


Highest-priority first order

When an unavailable semaphore becomes


available

Kernel allow the first task in the task-waiting list


to acquire it

Semaphore (Cont.)

Semaphores

Binary semaphores
Counting semaphores
Mutual-exclusion (mutex) semaphores

Binary Semaphores

Have a value of either 0 or 1

When a binary semaphore is first created

0: the semaphore is considered unavailable


1: the semaphore is considered available
It can be initialized to either available or unavailable (1 or
0, respectively)

When created as global resources

They are shared among all tasks


Any task would release a binary semaphore even if the
task did not initially acquire it

The State Diagram of a Binary


Semaphore

Counting Semaphores

Use a counter to allow it to be acquired or


released multiple times
The semaphore count assigned when it first
created denotes the number of semaphores
tokens it has initially
Global resources

The State Diagram of a Counting


Semaphore

Counting Semaphores (Cont.)

Bounded count

A count in which the initial count set for the counting


semaphore
Act as the maximum count for the semaphore
Determined when the semaphore was first created

Unbounded count

Allow the counting semaphore to count beyond the initial


count to the maximum value that can be held by the
counters data type

For example, an unsigned integer or an unsigned long value

Mutual Exclusion (Mutex)


Semaphores

A special binary semaphore that supports

The states of a mutex

Ownership
Recursive access
Task deletion safety
One or more protocols avoiding problems inherent to
mutual exclusions
Locked and unlocked

A mutex is initially created in the unlocked state

The State Diagram of a Mutual


Exclusion (Mutex) Semaphore

Mutex Ownership

Ownership of a mutex is gained when a task


first locks the mutex
When a task owns the mutex

No other task can lock or unlock that mutex


Contrast to the binary semaphore that can be
released by any task

Recursive Locking

Allow a task that owns the mutex to acquire it


multiple times in the locked state
The mutex with recursive locking is called a
recursive mutex

Useful when a task requiring exclusive access to


a shared resource calls one or more routines that
also require access to the same resource

Recursive Locking (Cont.)

Implementation

A lock count keep track of

Two states of a mutex

And the number of times it has been recursively locked

0 for unlocked and 1 for locked


Lock count > 1

Implementation: a mutex might maintain two counts

A binary value to track its state


A separate lock count to track the number of times it has been
acquired in the lock state by the task owns it

Recursive Locking (Cont.)

Comparison

The count used for the mutex

Track the number of times that the task owning the


mutex has locked or unlocked the mutex
Always unbounded,

Allows multiple recursive accesses

The count used for the counting semaphore

Track the number of tokens that have been acquired or


released by any task

Task Deletion Safety

Premature task deletion is avoided


While a task owns the mutex with task
deletion safety capability, the task cannot be
deleted

Priority Inversion Avoidance

When a higher priority task is blocked and is


waiting for a resource being used by a lower
priority task, which has itself been preempted
by an unrelated medium-priority task
Solutions

Priority inheritance protocol


Ceiling priority protocol

Chapter 16 will discuss in more detail

6.3 Typical Semaphore Operations

Creating and deleting semaphores


Acquiring and releasing semaphores
Clearing a semaphores task-waiting list
Getting semaphore information

Creating and Deleting Semaphores

Different calls might be used for creating


binary, counting, and mutex semaphores

Binary: specify the initial semaphore state and


the task-waiting order
Counting: specify the initial semaphore count and
the task-waiting order
Mutex: specify the task-waiting order and enable
task deletion safety, recursion, and priorityinversion avoidance protocols

Creating and Deleting Semaphores


(Cont.)

When a semaphore is deleted

Blocked tasks in its task-waiting list are


unblocked and moved to the ready or running
states

Do not delete a semaphore while it is in use

Acquiring and Releasing


Semaphores

Tasks acquires a semaphore in one of the


following ways

Wait forever: task remains blocked until it is


able to acquire a semaphore
Wait with a timeout: task remains blocked until
it is able to acquire a semaphore or until a set
interval of time (called timeout interval) passes
Do not wait: if not available, task does not block

Acquiring and Releasing


Semaphores (Cont.)

ISRs

Can also release binary and counting semaphores


Meaningless to lock or unlock binary semaphores,
counting semaphores, and mutex

Any task can release a binary or counting semaphore

However, a mutex can only be released (unlocked) by the


task that first acquired (locked)

Clearing Semaphore Task-Waiting


Lists

Free all tasks waiting in the semaphores task


waiting list
Useful for thread rendezvous

When multiple tasks executions need to meet at


some point in time to synchronize execution
control

Getting Semaphore Information

Useful for performing monitoring or


debugging
Should be used judiciously

The semaphore information might be dynamic at


the time it is requested

6.4 Typical Semaphore Use

Semaphore

Synchronize execution of multiple tasks


Coordinate access to a shared resource

Examples

Wait-and-signal synchronization
Multiple-task wait-and-signal synchronization
Credit-tracking synchronization
Single shared-resource-access synchronization
Recursive shared-resource-access synchronization
Multiple shared-resource-access synchronization

Wait-and-Signal Synchronization

Example

Binary semaphore is initially unavailable


tWaitTask has higher priority and runs first

Acquire the semaphore but blocked

tSignTask has a chance to run

Release semaphore and thus unlock tWaitTask

Wait-and-Signal Synchronization
Between Two Tasks

Multi-Task Wait-and-Signal
Synchronization

To coordinate the synchronization of more than two


tasks

Use the flush operation on the task-waiting list of a binary


semaphore

Example

Binary semaphore is initially unavailable


tWaitTask has higher priority and runs first

Acquire the semaphore but blocked

tSignalTask has a chance to run

Invoke a flush operation and thus unlock the three tWaitTask

Multi-Task Wait-and-Signal
Synchronization

Credit-Tracking Synchronization

The rate at which the signaling task executes is


higher than that of the signaled task

Need to count each signaling occurrence

By means of the counting semaphore

Credit-Tracking Synchronization
Between Two Tasks

Example

Counting semaphores count is initially 0


tSignalTask has higher priority than tWaitTask

tSignalTask continues to run until it relinquishes the CPU


by making a blocking system call or delaying itself
Thus, tSignalTask might increment the counting
semaphore multiple times before tWaitTask task running

The counting semaphore allows a credit buildup of


the number of times that the tWaitTask can execute
before the semaphore becomes available

Credit-Tracking Synchronization
(Cont.)

Credit-tracking mechanism is useful if


tSignalTask releases semaphore in bursts

Giving tWaitTask the chance to catch up every


once in a while

Useful in ISR handling to signal task waiting


on a semaphore

Single Shared-Resource-Access
Synchronization

Provide for mutually exclusive access shared


resources
A shared resource may be a

Memory location
A data structure
An I/O devices

Example

Use a binary semaphore to protect the shared


resource

Single Shared-Resource-Access
Synchronization

Single Shared-Resource-Access
Synchronization (Cont.)

Dangers

Any task can accidentally release the binary


semaphore, even never acquired the semaphore
first

Both tasks can access the shared resource at the same


time

Solutions

Use a mutex semaphore instead

Support the concept of ownership

Recursive Shared-Resource-Access
Synchronization

In some cases, a task must be able to access a


shared resource recursively

Example

tAccessTask calls Routine A that calls Routine B


All three need access to the same shared resource
If semaphore is used

tAccessTask would end up blocking and causing a


deadlock

Solution

Use a recursive mutex

Recursive Shared-Resource-Access
Synchronization

Pseudo Code for Recursively


Accessing a Shared Resource

Multiple Shared-Resource-Access
Synchronization

If multiple equivalent shared resources are


used

May use a counting semaphore that is initially set


to the number of equivalent shared resource

However, as with the binary semaphore

May cause problem if a task release a semaphore


that it did not originally acquire

Multiple Shared-Resource-Access
Synchronization

Pseudo Code: Use the Counting


Semaphore

Multiple Shared-Resource-Access
Synchronization (Cont.)

Solution

A separate mutex can be assigned for each shared


resource
Acquire the first mutex in a non-blocking way
If unsuccessful, acquire the second mutex in a
blocking-way

Pseudo Code: Use the Mutex

You might also like