Книга: Programming with POSIX® Threads

3.2.2.1 Nonblocking mutex locks

3.2.2.1 Nonblocking mutex locks

When you lock a mutex by calling pthread_mutex_lock, the calling thread will block if the mutex is already locked. Normally, that's what you want. But occasionally you want your code to take some alternate path if the mutex is locked. Your program may be able to do useful work instead of waiting. Pthreads provides the pthread_mutex_trylock function, which will return an error status (EBUSY) instead of blocking if the mutex is already locked.

When you use a nonblocking mutex lock, be careful to unlock the mutex only if pthread_mutex_trylock returned with success status. Only the thread that owns a mutex may unlock it. An erroneous call to pthread_mutex_unlock may return an error, or it may unlock the mutex while some other thread relies on having it locked—and that will probably cause your program to break in ways that may be very difficult to debug.

The following program, trylock.c, uses pthread_mutex_trylock to occasionally report the value of a counter—but only when its access does not conflict with the counting thread.

4 This definition controls how long counter_thread holds the mutex while updating the counter. Making this number larger increases the chance that the pthread_mutex_trylock in monitor_thread will occasionally return EBUSY.

14-39 The counter_thread wakes up approximately each second, locks the mutex, and spins for a while, incrementing counter. The counter is therefore increased by SPIN each second.

46-72 The monitor_thread wakes up every three seconds, and tries to lock the mutex. If the attempt fails with EBUSY, monitor_thread counts the failure and waits another three seconds. If the pthread_mutex_trylock succeeds, then monitor_thread prints the current value of counter (scaled by SPIN).

80-88 On Solaris 2.5, call thr_setconcurrency to set the thread concurrency level to 2. This allows the counter_thread and monitor_thread to run concurrently on a uniprocessor. Otherwise, monitor_thread would not run until counter_ thread terminated.

? trylock.c

1 #include <pthread.h>
2 #include "errors.h" 3
4 #define SPIN 10000000 5
6 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
7 long counter;
8 time_t end_time;

9
10 /*
11 * Thread start routine that repeatedly locks a mutex and
12 * increments a counter.
13 */
14 void *counter_thread (void *arg)
15 {
16 int status;
17 int spin;

18
19 /*
20 * Until end_time, increment the counter each second. Instead of
21 * just incrementing the counter, it sleeps for another second
22 * with the mutex locked, to give monitor_thread a reasonable
23 * chance of running.
24 */
25 while (time (NULL) < end_time)
26 {
27  status = pthread_mutex_lock (&mutex);
28  if (status != 0)
29  err_abort (status, "Lock mutex");
30  for (spin = 0; spin < SPIN; spin++)
31  counter++;
32  status = pthread_mutex_unlock (&mutex);
33  if (status != 0)
34  err_abort (status, "Unlock mutex");
35  sleep (1);
36 }
37 printf ("Counter is %#lxn", counter);
38 return NULL;
39 }

40
41 /*
42 * Thread start routine to "monitor" the counter. Every 3
43 * seconds, try to lock the mutex and read the counter. If the
44 * trylock fails, skip this cycle.
45 */
46 void *monitor_thread (void *arg)
47 {
48 int status;
49 int misses = 0;

50
51
52 /*
53 * Loop until end_time, checking the counter every 3 seconds.
54 */
55 while (time (NULL) < end_time)
56 {
57  sleep (3);
58  status = pthread_mutex_trylock (&mutex);
59  if (status != EBUSY)
60  {
61  if (status != 0)
62  err_abort (status, "Trylock mutex");
63  printf ("Counter is %ldn", counter/SPIN);
64  status = pthread_mutex_unlock (&mutex);
65  if (status != 0)
66  err_abort (status, "Unlock mutex");
67  } else
68  misses++; /* Count "misses" on the lock */
69  }
70  printf ("Monitor thread missed update %d times.n", misses);
71 return NULL;
72 }
73
74 int main (int argc, char *argv[])
75 {
76 int status;
77 pthread_t counter_thread_id;
78 pthread_t monitor_thread_id; 79
80 #ifdef sun
81 /*
82 * On Solaris 2.5, threads are not timesliced. To ensure
83 * that our threads can run concurrently, we need to
84 * increase the concurrency level to 2.
85 */
86 DPRINTF (("Setting concurrency level to 2n"));
87 thr_setconcurrency (2);
88 #endif 89
90 end_time = time (NULL) + 60; /* Run for 1 minute */
91 status = pthread_create (
92  &counter_thread_id, NULL, counter_thread, NULL);
93 if (status != 0)
94  err_abort (status, "Create counter thread");
95 status = pthread_create (
96  &monitor_thread_id, NULL, monitor_thread, NULL);
97 if (status != 0)
98  err_abort (status, "Create monitor thread");
99 status = pthread_join (counter_thread_id, NULL);
100 if (status != 0)
101  err_abort (status, "Join counter thread");
102 status = pthread_join (monitor_thread_id, NULL);
103 if (status != 0)
104  err_abort (status, "Join monitor thread");
105 return 0;
106 }

Оглавление книги

Оглавление статьи/книги

Генерация: 1.107. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз