If variable status contains the return value TX_SUCCESS, we have successfully obtained an instance of the counting semaphore called my_semaphore.. TX_SEMAPHORE my_semaphore; UINT status
Trang 1receive a TX_DELETED return status Make certain that you don’t try to use a deleted semaphore Figure 11.5 shows how a counting semaphore can be deleted
If variable status contains the return value TX_SUCCESS, we have successfully deleted
the counting semaphore
11.8 Getting an Instance of a Counting Semaphore
The tx_semaphore_get service retrieves an instance (a single count) from the specifi ed counting semaphore If this call succeeds, the semaphore count decreases by one Figure 11.6 shows how to get an instance of a counting semaphore, where we use the wait option value TX_WAIT_FOREVER
If variable status contains the return value TX_SUCCESS, we have successfully obtained
an instance of the counting semaphore called my_semaphore
TX_SEMAPHORE my_semaphore;
UINT status;
/* Create a counting semaphore with an initial value of 1.
This is typically the technique used to create a binary semaphore Binary semaphores are used to provide
protection over a common resource */
status = tx_semaphore_create(&my_semaphore, "my_semaphore_name", 1);
/* If status equals TX_SUCCESS, my_semaphore is ready for use */
Figure 11.4: Creating a counting semaphore
TX_SEMAPHORE my_semaphore;
UINT status;
… /* Delete counting semaphore Assume that the counting semaphore has already been created */
status = tx_semaphore_delete(&my_semaphore);
/* If status equals TX_SUCCESS, the counting semaphore has been deleted */
Figure 11.5: Deleting a counting semaphore
Trang 211.9 Retrieving Information about Counting Semaphores
There are three services that enable you to retrieve vital information about semaphores The fi rst such service for semaphores — the tx_semaphore_info_get service — retrieves
a subset of information from the Semaphore Control Block This information provides
a “ snapshot ” at a particular instant in time, i.e., when the service is invoked The
other two services provide summary information that is based on the gathering of
run-time performance data One service — the tx_semaphore_performance_info_get
service — provides an information summary for a particular semaphore up to the time the service is invoked By contrast the tx_semaphore_performance_system_info_get retrieves an information summary for all semaphores in the system up to the time the service is invoked These services are useful in analyzing the behavior of the system and determining whether there are potential problem areas The tx_semaphore_info_get3
service retrieves several useful pieces of information about a counting semaphore
The information that is retrieved includes the counting semaphore name, its current
count, the number of threads suspended for this semaphore, and a pointer to the next
created counting semaphore Figure 11.7 shows how this service can be used to obtain information about a counting semaphore
TX_SEMAPHORE my_semaphore;
UINT status;
… /* Get a semaphore instance from the semaphore "my_semaphore." If the semaphore count is zero, suspend until an instance becomes available.
Note that this suspension is only possible from application threads */
status = tx_semaphore_get(&my_semaphore, TX_WAIT_FOREVER);
/* If status equals TX_SUCCESS, the thread has obtained an instance of the semaphore */
Figure 11.6: Get an instance from a counting semaphore
3 By default, only the tx_semaphore_info_get service is enabled The other two information
gathering services must be enabled in order to use them
Trang 3If variable status contains the return value TX_SUCCESS, we have obtained valid
information about the counting semaphore called my_semaphore
11.10 Prioritizing a Counting Semaphore Suspension List
When a thread is suspended because it is waiting for a counting semaphore, it is placed
in the suspension list in a FIFO manner When a counting semaphore instance becomes available, the fi rst thread in that suspension list (regardless of priority) obtains ownership
of that instance The tx_semaphore_prioritize service places the highest-priority thread suspended on a specifi c counting semaphore at the front of the suspension list All other threads remain in the same FIFO order in which they were suspended Figure 11.8 shows how this service can be used
If variable status contains the return value TX_SUCCESS, the highest-priority thread
suspended on an instance of my_semaphore has been placed at the front of the suspension list
11.11 Placing an Instance in a Counting Semaphore
The tx_semaphore_put service places an instance in a counting semaphore, i.e., it
increases the count by one If there is a thread suspended on this semaphore when the put
TX_SEMAPHORE my_semaphore;
CHAR *name;
ULONG current_value;
TX_THREAD *first_suspended;
ULONG suspended_count;
TX_SEMAPHORE *next_semaphore;
UINT status;
… /* Retrieve information about the previously created semaphore "my_semaphore." */
status = tx_semaphore_info_get(&my_semaphore, &name, ¤t_value, &first_suspended, &suspended_count, &next_semaphore);
/* If status equals TX_SUCCESS, the information requested is valid */
Figure 11.7: Get information about a counting semaphore
Trang 4service is performed, the suspended thread’s get operation completes and that thread is resumed Figure 11.9 shows how this service can be used
If variable status contains the return value TX_SUCCESS, the semaphore count has been
incremented (an instance has been placed in the semaphore) If a thread was suspended for this semaphore, then that thread receives this instance and resumes execution
11.12 Placing an Instance in a Semaphore Using a Ceiling
The tx_semaphore_put service places an instance in a counting semaphore without
regard to the current count of the semaphore However, if you want to make certain that
TX_SEMAPHORE my_semaphore;
UINT status;
/* Ensure that the highest priority thread will receive the next instance of this semaphore */
… status = tx_semaphore_prioritize(&my_semaphore);
/* If status equals TX_SUCCESS, the highest priority suspended thread is at the front of the list The next tx_semaphore_put call made to this semaphore will wake up this thread */
Figure 11.8: Prioritize the counting semaphore suspension list
TX_SEMAPHORE my_semaphore;
UINT status;
… /* Increment the counting semaphore "my_semaphore." */
status = tx_semaphore_put(&my_semaphore);
/* If status equals TX_SUCCESS, the semaphore count has been incremented Of course, if a thread was waiting,
it was given the semaphore instance and resumed */
Figure 11.9: Place an instance on a counting semaphore
Trang 5the count is always less than or equal to a certain value, use the tx_semaphore_ceiling_ put service When this service is invoked, the semaphore is incremented only if the
resulting count would be less than or equal to the ceiling value Figure 11.10 shows how this service can be used
11.13 Semaphore Notifi cation and Event-Chaining 4
The tx_semaphore_put_notify service registers a notifi cation callback function that is invoked whenever an instance is placed on the specifi ed semaphore The processing of the notifi cation callback is defi ned by the application This is an example of event-chaining where notifi cation services are used to chain various synchronization events together This is typically useful when a single thread must process multiple synchronization
events
11.14 Comparing a Counting Semaphore with a Mutex
A counting semaphore resembles a mutex in several respects, but there are differences,
as well as reasons to use one resource over the other Figure 11.11 reproduces the
comparison chart for these two objects, which fi rst appeared in Chapter 4
TX_SEMAPHORE my_semaphore;
UINT status;
…
/* Increment the semaphore "my_semaphore" using a ceiling */
status = tx_semaphore_ceiling_put(&my_semaphore, 3);
/* If status equals TX_SUCCESS, the semaphore count has
been incremented Of course, if a thread was waiting,
it was given the semaphore instance and resumed.
If status equals TX_CEILING_EXCEEDED than the semaphore is not
incremented because the resulting value would have been greater Than the ceiling value of 3 */
Figure 11.10: Place an instance on a semaphore using a ceiling
4 Event-chaining is a trademark of Express Logic, Inc
Trang 6A mutex is exceptionally robust in providing mutual exclusion If this is crucial to your application, then using a mutex is a good decision However, if mutual exclusion is not
a major factor in your application, then use a counting semaphore because it is slightly faster and uses fewer system resources
To illustrate the use of a counting semaphore, we will replace a mutex with a binary
semaphore in the next sample system
11.15 Sample System Using a Binary Semaphore in Place
of a Mutex
This sample system is a modifi cation of the one discussed in the preceding chapter The only goal here is to replace the mutex from that system with a binary semaphore We will retain the timing facilities of that system to compare the results of thread processing by using a mutex versus using a binary semaphore
Mutex Counting Semaphore
semaphore
Semaphore is generally faster than a mutex and requires fewer system resources
Thread
ownership
Only one thread can own
a mutex
No concept of thread ownership for a semaphore – any thread can decrement a counting semaphore
if its current count exceeds zero Priority
inheritance
Available only with a mutex
Feature not available for semaphores
Mutual exclusion
Primary purpose of a mutex – a mutex should
be used only for mutual exclusion
Can be accomplished with the use of a binary semaphore, but there may be pitfalls
Inter-thread
synchronization
Do not use a mutex for this purpose
Can be performed with a semaphore, but an event flags group should be considered also Event
notification
Do not use a mutex for this purpose
Can be performed with a semaphore
Thread
suspension
Thread can suspend if another thread already owns the mutex (depends
on value of wait option)
Thread can suspend if the value
of a counting semaphore is zero (depends on value of wait option)
Figure 11.11: Comparison of a mutex with a counting semaphore
Trang 7Figure 11.12 shows a modifi cation of the Speedy_Thread activities, in which we have replaced references to a mutex with references to a binary semaphore The priorities and times remain the same as in the previous system The shaded boxes represent the critical sections
Figure 11.13 shows a modifi cation of the Slow_Thread activities The only change we have made is to replace references to mutexes with references to binary semaphores
In Chapter 10, we created a sample system that produced output that began as follows:
**** Timing Info Summary
Current Time: 500
Speedy_Thread counter: 22
Speedy_Thread avg time: 22
Slow_Thread counter: 11
Slow_Thread avg time: 42
We want our new sample system to perform the same operations as the previous system
We will discuss a series of changes to be applied to the previous system so that all
references to a mutex will be replaced with references to a binary semaphore The
Activity 1
Sleep 2 ticks
Activity 3
Sleep 4 ticks
Activity 2
Get and hold binary semaphore for 5 ticks
Activity 4
Get and hold binary semaphore for 3 ticks
Figure 11.12: Activities of the Speedy_Thread (priority 5)
Activity 6
Sleep 8 ticks
Activity 8
Sleep 9 ticks
Activity 5
Get and hold binary
semaphore for 12 ticks
Activity 7
Get and hold binary semaphore for 11 ticks
Figure 11.13: Activities of the Slow_Thread (priority 15)
Trang 8complete program listing, called 11a_sample_system.c, is located in the next section of
this chapter and on the attached CD
The fi rst change occurs in the declaration and defi nitions section of our program, where
we replace the declaration of a mutex with the declaration of a binary semaphore, as
follows
TX_SEMAPHORE my_semaphore;
A binary semaphore is a special case of a counting semaphore, so the declaration of each
is the same The next change occurs in the application defi nitions section of our program, where we replace the creation of a mutex with the creation of a binary semaphore, as follows:
/* Create the binary semaphore used by both threads */
tx_semaphore_create( & my_semaphore, “my_semaphore”, 1);
There are two primary differences between the defi nition of a mutex and the defi nition
of a binary semaphore First, only mutexes support priority inheritance, so that option does not appear in the argument list for semaphore creation Second, only semaphores have counts, so the argument list must include an initial value In the above semaphore creation, the initial count is one (1), which is the most commonly used initial value for a binary semaphore 5 This means that the binary semaphore has one instance available that may be obtained by a thread
The remaining changes occur in the function defi nitions section of our program We need
to change all references to mutexes to binary semaphores to protect critical sections in Activities 2 and 4 for the Speedy_Thread, and Activities 5 and 7 for the Slow_Thread
We will show only the changes for the Speedy_Thread and will leave the Slow_Thread changes as an exercise for the reader Figure 11.14 contains the necessary changes
for Activity 2 Most of the modifi cations involve changing references to a mutex with references to a binary semaphore
Figure 11.15 contains the necessary changes for Activity 4 Most of the modifi cations involve changing references to a mutex with references to a binary semaphore
5 The only other possible value is zero (0) It is rarely used as an initial value for a binary
semaphore
Trang 911.16 Listing for 11a_sample_system.c
The sample system named 11a_sample_system.c is located on the attached CD The
complete listing appears below; line numbers have been added for easy reference
001 /* 11a_sample_system.c
002
003 Create two threads, and one mutex
004 Use arrays for the thread stacks
005 A binary semaphore protects the critical sections
006 Use an application timer to display thread timings */
007
008 /****************************************************/
009 /* Declarations, Defi nitions, and Prototypes */
010 /****************************************************/
011
/* Activity 4: 3 timer-ticks *** critical section ***
Get an instance of the binary semaphore with suspension */
status = tx_semaphore_get(&my_semaphore, TX_WAIT_FOREVER);
if (status != TX_SUCCESS) break; /* Check status */
tx_thread_sleep(3);
/* Place an instance in the binary semaphore */
status = tx_semaphore_put(&my_semaphore);
if (status != TX_SUCCESS) break; /* Check status */
Figure 11.15: Changes to Activity 4
/* Activity 2: 5 timer-ticks *** critical section ***
Get an instance of the binary semaphore with suspension */
status = tx_semaphore_get(&my_semaphore, TX_WAIT_FOREVER);
if (status != TX_SUCCESS) break; /* Check status */
tx_thread_sleep(5);
/* Place an instance in the binary semaphore */
status = tx_semaphore_put(&my_semaphore);
if (status != TX_SUCCESS) break; /* Check status */
Figure 11.14: Changes to Activity 2
Trang 10012
013 #include “tx_api.h”
014 #include stdio.h
015
016 #defi ne STACK_SIZE 1024
017
018 CHAR stack_speedy[STACK_SIZE];
019 CHAR stack_slow[STACK_SIZE];
020
021
022 /* Defi ne the ThreadX object control blocks */
023
024 TX_THREAD Speedy_Thread;
025 TX_THREAD Slow_Thread;
026
027 TX_SEMAPHORE my_semaphore;
028
029 /* Declare the application timer */
030 TX_TIMER stats_timer;
031
032 /* Declare the counters and accumulators */
033 ULONG Speedy_Thread_counter = 0,
034 total_speedy_time = 0;
035 ULONG Slow_Thread_counter = 0,
036 total_slow_time = 0;
037
038 /* Defi ne prototype for expiration function */
039 void print_stats(ULONG);
040
041 /* Defi ne thread prototypes */
042
043 void Speedy_Thread_entry(ULONG thread_input);
044 void Slow_Thread_entry(ULONG thread_input);
045
046 /****************************************************/
047 /* Main Entry Point */
048 /****************************************************/
049
050 /* Defi ne main entry point */
051