Back to Blog

VxWorks Inter-Process Communication 2 -- Semaphores

#semaphore#Task#Optimization#delete#Work

VxWorks Inter-Process Communication 2 -- Semaphores

I. Concept of Semaphores

Semaphores are the primary mechanism for achieving task mutual exclusion and synchronization. The semaphores provided by VxWorks are highly optimized and are the fastest among all inter-task communication mechanisms.

II. Classification of Semaphores

Binary Semaphores: The optimal way to achieve mutual exclusion and synchronization; fastest and most commonly used.

Mutual Exclusion Semaphores: A special type of binary semaphore, specifically optimized for mutual exclusion operations.

Counting Semaphores: Similar to binary semaphores, they can record the number of times a semaphore has been released and can monitor multiple instances of the same resource.

III. Binary Semaphores

Tasks often wait for events or need to acquire resources. Polling is generally not allowed in Real-Time systems; it's best to use Pending to wait for events or resources.

State Diagram:

Explanation:

  1. Call semBCreate() for a resource to create a binary semaphore and specify:

SEM_Full (resource available) SEM_Empty (resource unavailable).

  1. When the resource is unavailable, the Task calls semTake() to enter Pending until the semaphore is Given.

Related Functions:

[c-sharp] view plain copy

  1. SEM_ID semBCreate  

  2. (  

  3.     int         options,      /* semaphore options */  

  4.     SEM_B_STATE initialState  /* initial semaphore state */  

  5. )  

  6. STATUS semTake  

  7. (  

  8.     SEM_ID semId, /* ID of the semaphore to acquire */  

  9.     int timeout /* timeout (ticks)/no-wait/forever */  

  10. )  

ISR (Interrupt Service Routine) cannot call semTake()!

[c-sharp] view plain copy

  1. STATUS semGive  
  2. (  
  3.     SEM_ID semId /* ID of the semaphore to release */  
  4. )  

[c-sharp] view plain copy

  1. semFlush()  

Application Directions:

1. Mutual Exclusion Operations: Refers to different tasks using semaphores to mutually exclusively access critical resources. This method of mutual exclusion offers finer granularity compared to interrupt disabling and preemptive locks.

For mutual exclusion operations, the initial state is set to (SEM_FULL) available. semTake() and semGive() are called in pairs and sequentially within the same Task.

2. Synchronization Operations: Refers to a task using semaphores to control its execution progress, synchronizing itself with a set of external events. For synchronization operations, the initial state is set to (SEM_EMPTY) unavailable. semTake() and semGive() are called separately in different Tasks.

IV. Mutual Exclusion Semaphores

Mutual exclusion semaphores are a special type of binary semaphore designed to address some issues that arise when using binary semaphores for mutual exclusion. Mutual exclusion semaphores primarily add handling for priority inversion, deletion safety, and recursive access.

State Diagram:

Related Functions:

[c-sharp] view plain copy

  1. SEM_ID semMCreate  
  2. (  
  3.     int options               /* mutex semaphore options */  
  4. )  

Differences:

  1. Mutual exclusion semaphores can only be used for mutual exclusion operations.

  2. Only the task that has acquired the mutual exclusion semaphore can release it.

  3. Interrupt Service Routines (ISRs) cannot release (semGive()) mutual exclusion semaphores.

  4. Mutual exclusion semaphores do not support semFlush() operations.

Application Directions:

1. Avoiding Priority Inversion:

In the figure above, task2 waits for task1's resource and thus enters a Pend state. At this point, a medium-priority task enters and preempts task1's CPU. The result is that a lower-priority task executes before the higher-priority task2. This phenomenon is called priority inversion.

Using semId = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE); can prevent inversion.

At this point, task1's priority is elevated to be the same as task2's until task2 completes execution.

SEM_INVERSION_SAFE cannot be paired with SEM_Q_FIFO!

2. Deletion Safety

Using: semId = semMCreate(SEM_Q_FIFO | SEM_DELETE_SAFE); can achieve safe deletion.

Its essence is: before a Task performs a semTake() operation on a mutual exclusion semaphore and successfully acquires it, a taskSafe() operation is implicitly executed; after performing a semGive() operation, a taskUnsafe() operation is implicitly executed.

If task1 attempts to delete task2, which is already protected, task1 will be blocked until task2 is unprotected (releases the mutual exclusion semaphore with deletion protection) before the deletion can be completed.

3. Recursive Access

[c-sharp] view plain copy

  1. InitFun()  

  2. {  

  3.     sem_ID = semMCreate(…);  

  4. }  

  5. funB()  

  6. {  

  7.     semTake(sem_ID, SEM_FOREVER);  

  8.     /* Access critical resource */  

  9.     semGive(sem_ID);  

  10. }  

  11. funA()  

  12. {  

  13.     semTake(sem_ID, SEM_FOREVER);  

  14.     /* Access critical resource */  

  15.     funB();  // Recursive access, without deadlock  

  16.     semGive(sem_ID);  

  17. }  

V. Counting Semaphores

Both counting semaphores and binary semaphores can be used for synchronization and mutual exclusion between tasks. The difference is that counting semaphores can record the number of times a semaphore has been released, which can be used to monitor the usage status of a particular resource.

State Diagram:

Related Functions:

[c-sharp] view plain copy

  1. SEM_ID semCCreate  

  2. (  

  3.     int options,              /* semaphore option modes */  

  4.     int initialCount          /* initial count */  

  5. )