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 %#lx
', 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 %ld
', 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.
', 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 2
'));
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 }
3.2.3 Using mutexes for atomicity
Invariants, as we saw in Section 3.1, are statements about your program that must always be true. But we also saw that invariants probably aren't always true, and many can't be. To be always true, data composing an invariant must be modified atomically. Yet it is rarely possible to make multiple changes to a program state