Embry-Riddle Real-Time Laboratory Experiment
Experiment #3
Semaphores


Introduction

Semaphores permit multitasking applications to coordinate their activities. The most obvious way for tasks to communicate is via various shared data structures. Because all tasks in VxWorks exist in a single linear address space, shared data structures between tasks is trivial. Global variables, linear buffers, ring buffers, link lists, and pointers can be referenced directly by code running in different context.

However, while shared address space simplifies the exchange of data, interlocking access to memory is crucial to avoid contention. Many methods exist for obtaining exclusive access to resources, and one of them is semaphores.


Objectives

The following are the primary objectives of this experiment:


Description

VxWorks semaphores are highly optimized and provide the fastest intertask communication mechanisms in VxWorks. Semaphores are the primary means for addressing the requirements of both mutual exclusion and task synchronization.

The are three types of Wind semaphores, optimized to address different classes of problems:

binary

mutual exclusion

counting

1. Semaphore Control

Wind semaphores provide a single uniform interface for semaphore control. Only the creation routines are specific to the semaphore type:

Please refer to the VxWorks Reference Manual for valid arguments in the above routines.

2. Example: Binary Semaphore

A binary semaphore can be viewed as a flag that is available or unavailable. When a task takes a binary semaphore, using semTake(), the outcome depends on whether the semaphore is available or unavailable at the time of the call. If the semaphore is available, then the semaphore becomes unavailable and then the task continues executing immediately. If the semaphore is unavailable, the task is put on a queue of blocked tasks and enters a state of pending on the availability of the semaphore.

When a task gives a binary semaphore, using semGive(), the outcome depends on whether the semaphore is available or unavailable at the time of the call.If the semaphore is already available, giving the semaphore has no effect at all. If the semaphore is unavailable and no task is waiting to take it, then the semaphore becomes available. If the semaphore is unavailable and one or more tasks are pending on its availablity, then the first task in the queue of pending tasks is unblocked, and the semaphore is left unavailable.

In the example below, two tasks(taskOne and taskTwo), are competing to update the value of a global variable, called "global." The objective of the program is to toggle the value of the global variable(1s and 0s). taskOne changes the value of "global" to 1 and taskTwo changes the value back to 0.

Without the use of the semaphore, the value of "global" would be random and the value of "global" would be corrupted.
-------------------------------------------------------------------------------------
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "semLib.h"
#include "stdio.h"

/* function prototypes */
void taskOne(void);
void taskTwo(void);

/* globals */
#define ITER 10
SEM_ID semBinary;
int global = 0;

void binary(void)
{
int taskIdOne, taskIdTwo;

/* create semaphore with semaphore available and queue tasks on FIFO basis */
semBinary = semBCreate(SEM_Q_FIFO, SEM_FULL);

/* Note 1: lock the semaphore for scheduling purposes */
semTake(semBinary,WAIT_FOREVER);

/* spawn the two tasks */
taskIdOne = taskSpawn("t1",90,0x100,2000,(FUNCPTR)taskOne,0,0,0,0,0,0,0,0,0,0);
taskIdTwo = taskSpawn("t2",90,0x100,2000,(FUNCPTR)taskTwo,0,0,0,0,0,0,0,0,0,0);
}


void taskOne(void)
{
int i;
for (i=0; i < ITER; i++)
	{
	semTake(semBinary,WAIT_FOREVER); /* wait indefinitely for semaphore */
	printf("I am taskOne and global = %d......................\n", ++global);
	semGive(semBinary); /* give up semaphore */
	} 
}

void taskTwo(void)
{
int i;
semGive(semBinary); /* Note 2: give up semaphore(a scheduling fix) */
for (i=0; i < ITER; i++)
	{
	semTake(semBinary,WAIT_FOREVER); /* wait indefinitely for semaphore */
	printf("I am taskTwo and global = %d----------------------\n", --global);
	semGive(semBinary); /* give up semaphore */
	} 
}
-------------------------------------------------------------------------------------


Procedures

1. Copy the source code in the example and compile it.

2. Load the object file onto the target machine.

3. Run the examples by executing the main routine("binary",etc.) of the example on WindSh terminal.

Note: Make sure you have redirected I/O, otherwise you won't see the results of the printf commands.

Follow On Experiment

Experiment 1. In the binary semaphore example, remove the source code associated with comments Notes 1 and Notes 2. Compile and run the program. Is there a difference in the output? Is so, explain the reasons why.

Experiment 2. Write a program that toggles the value of "global" between 1 and 0 using counting semaphores. Just edit the example code to make appropriate modifications.


Additional Information

Refer to VxWorks User's Manual and Reference Manual.


Return to Primary Table of Contents


Last Updated: 16 March 1997
Created by: Dan Eyassu
eyassud@db.erau.edu