(and a good idea) to unlock and destroy the mutex before freeing the storage that the mutex occupies.

3.2.2 Locking and unlocking a mutex

int pthread_mutex_lock (pthread_mutex_t *mutex);

int pthread_mutex_trylock (pthread_mutex_t *mutex);

int pthread_mutex_unlock (pthread_mutex_t *mutex);

In the simplest case, using a mutex is easy. You lock the mutex by calling either pthread_mutex_lock or pthread_mutex_trylock, do something with the shared data, and then unlock the mutex by calling pthread_mutex_unlock. To make sure that a thread can read consistent values for a series of variables, you need to lock your mutex around any section of code that reads or writes those variables.

You cannot lock a mutex when the calling thread already has that mutex locked. The result of attempting to do so may be an error return, or it may be a self-deadlock, with the unfortunate thread waiting forever for itself to unlock the mutex. (If you have access to a system supporting the UNLX98 thread extensions, you can create mutexes of various types, including recursive mutexes, which allow a thread to relock a mutex it already owns. The mutex type attribute is discussed in Section 10.1.2.)

The following program, alarm_mutex.c, is an improved version of alarm_ thread.c (from Chapter 1). It lines up multiple alarm requests in a single 'alarm server' thread.

12-17 The alarm_t structure now contains an absolute time, as a standard UNIX time_t, which is the number of seconds from the UNIX Epoch (Jan 1 1970 00:00) to the expiration time. This is necessary so that alarm_t structures can be sorted by 'expiration time' instead of merely by the requested number of seconds. In addition, there is a link member to connect the list of alarms.

19-20 The alarm_mutex mutex coordinates access to the list head for alarm requests, called alarm_list. The mutex is statically initialized using default attributes, with the PTHREAD_MUTEX_INITIALIZER macro. The list head is initialized to NULL, or empty.

¦ alarm_mutex.c part 1 definitions

1 #include <pthread.h>

2 #include <time.h>

3 #include 'errors.h' 4

5 /*

6 * The 'alarm' structure now contains the time_t (time since the

7 * Epoch, in seconds) for each alarm, so that they can be

8 * sorted. Storing the requested number of seconds would not be

9 * enough, since the 'alarm thread' cannot tell how long it has

10 * been on the list.

11 */

12 typedef struct alarm_tag {

13 struct alarm_tag *link;

14 int seconds;

15 time_t time; /* seconds from EPOCH */

16 char message[64];

17 } alarm_t;

18

19 pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER;

20 alarm_t *alarm_list = NULL;

The code for the alarm_thread function follows. This function is run as a thread, and processes each alarm request in order from the list alarm_list. The thread never terminates—when main returns, the thread simply 'evaporates.' The only consequence of this is that any remaining alarms will not be delivered— the thread maintains no state that can be seen outside the process.

If you would prefer that the program process all outstanding alarm requests before exiting, you can easily modify the program to accomplish this. The main thread must notify alarm_thread, by some means, that it should terminate when it finds the alarm_list empty. You could, for example, have main set a new global variable alarm_done and then terminate using pthread_exit rather than exit. When alarm_thread finds alarm_list empty and alarm_done set, it would immediately call pthread_exit rather than waiting for a new entry.

29-30 If there are no alarms on the list, alarm_thread needs to block itself, with the mutex unlocked, at least for a short time, so that main will be able to add a new alarm. It does this by setting sleep_time to one second.

31-42 If an alarm is found, it is removed from the list. The current time is retrieved by calling the time function, and it is compared to the requested time for the alarm. If the alarm has already expired, then alarm_thread will set sleep_time to 0. If the alarm has not expired, alarm_thread computes the difference between the current time and the alarm expiration time, and sets sleep_time to that number of seconds.

52-58 The mutex is always unlocked before sleeping or yielding. If the mutex remained locked, then main would be unable to insert a new alarm on the list. That would make the program behave synchronously—the user would have to wait until the alarm expired before doing anything else. (The user would be able to enter a single command, but would not receive another prompt until the next alarm expired.) Calling sleep blocks alarm_thread for the required period of time—it cannot run until the timer expires.

Calling sched_yield instead is slightly different. We'll describe sched_yield in detail later (in Section 5.5.2)—for now, just remember that calling sched_yield will yield the processor to a thread that is ready to run, but will return immediately if there are no ready threads. In this case, it means that the main thread will be allowed to process a user command if there's input waiting—but if the user hasn't entered a command, sched_yield will return immediately.

64-67 If the alarm pointer is not NULL, that is, if an alarm was processed from alarm_list, the function prints a message indicating that the alarm has expired. After printing the message, it frees the alarm structure. The thread is now ready to process another alarm.

¦ alarm_mutex.c part 2 alarm_thread

1 /*

2 * The alarm thread's start routine.

3 */

4 void *alarm_thread (void *arg)

5 {

6 alarm_t *alarm;

7 int sleep_time;

8 time_t now;

9 int status; 10

11 /*

12 * Loop forever, processing commands. The alarm thread will

13 * be disintegrated when the process exits.

14 */

15 while (1) {

16 status = pthread_mutex_lock (&alarm_mutex);

17 if (status != 0)

18 err_abort (status, 'Lock mutex');

19 alarm = alarm_list; 20

21 /*

22 * If the alarm list is empty, wait for one second. This

23 * allows the main thread to run, and read another

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату