1 /* $OpenBSD: pthread_rwlock.c,v 1.3 2014/05/20 01:25:24 guenther Exp $ */ 2 /* PUBLIC DOMAIN Feb 2012 <guenther@openbsd.org> */ 3 4 #include <sys/types.h> 5 #include <assert.h> 6 #include <err.h> 7 #include <pthread.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <time.h> 11 #include <unistd.h> 12 13 /* 14 * Set up an rwlock with a few reader threads, start a writer blocking, 15 * then let go the reader threads one by one. Verify that the writer 16 * thread gets, gets out, and then the rwlock can be locked for reading 17 * again. 18 */ 19 20 pthread_rwlock_t rw; 21 22 pthread_mutex_t m; 23 pthread_cond_t c; 24 enum 25 { 26 UNLOCKED, 27 NUM_READERS = 6, 28 WRITE_STARTED, 29 WRITE, 30 WRITE_DONE, 31 } state; 32 time_t write_started; 33 34 static void * 35 reader(void *arg) 36 { 37 int me = *(int *)arg; 38 int diff; 39 40 pthread_mutex_lock(&m); 41 assert(state < NUM_READERS); 42 pthread_rwlock_rdlock(&rw); 43 state++; 44 printf("reader %d locked, state = %d\n", me, state); 45 pthread_cond_broadcast(&c); 46 pthread_mutex_unlock(&m); 47 48 pthread_mutex_lock(&m); 49 while (state < WRITE_STARTED) { 50 pthread_cond_wait(&c, &m); 51 printf("reader %d woken, state = %d\n", me, state); 52 } 53 54 diff = difftime(time(NULL), write_started); 55 if (diff < 2) 56 sleep(3 - diff); 57 58 pthread_rwlock_unlock(&rw); 59 printf("reader %d unlocked\n", me); 60 sleep(1); 61 62 pthread_mutex_unlock(&m); 63 64 pthread_mutex_lock(&m); 65 while (state >= WRITE_STARTED) { 66 pthread_cond_wait(&c, &m); 67 printf("reader %d woken, state = %d\n", me, state); 68 } 69 state++; 70 printf("reader %d trying again (%d)\n", me, state); 71 pthread_rwlock_rdlock(&rw); 72 printf("reader %d locked again (%d)\n", me, state); 73 pthread_cond_broadcast(&c); 74 while (state != NUM_READERS) { 75 pthread_cond_wait(&c, &m); 76 printf("reader %d woken, state = %d\n", me, state); 77 } 78 pthread_mutex_unlock(&m); 79 pthread_rwlock_unlock(&rw); 80 81 printf("reader %d exiting\n", me); 82 return NULL; 83 } 84 85 static void * 86 writer(void *arg) 87 { 88 pthread_mutex_lock(&m); 89 printf("writer started, state = %d\n", state); 90 while (state != NUM_READERS) { 91 pthread_cond_wait(&c, &m); 92 printf("writer woken, state = %d\n", state); 93 } 94 state = WRITE_STARTED; 95 printf("writer starting\n"); 96 write_started = time(NULL); 97 pthread_cond_broadcast(&c); 98 pthread_mutex_unlock(&m); 99 100 pthread_rwlock_wrlock(&rw); 101 printf("writer locked\n"); 102 103 pthread_mutex_lock(&m); 104 state = WRITE; 105 pthread_cond_broadcast(&c); 106 107 while (state == WRITE) 108 pthread_cond_wait(&c, &m); 109 110 printf("writer unlocking\n"); 111 pthread_rwlock_unlock(&rw); 112 state = UNLOCKED; 113 pthread_cond_broadcast(&c); 114 pthread_mutex_unlock(&m); 115 116 printf("writer exiting\n"); 117 return NULL; 118 } 119 120 121 int 122 main(void) 123 { 124 pthread_t tr[NUM_READERS], tw; 125 int ids[NUM_READERS], i, r; 126 127 pthread_rwlock_init(&rw, NULL); 128 pthread_mutex_init(&m, NULL); 129 pthread_cond_init(&c, NULL); 130 state = UNLOCKED; 131 132 for (i = 0; i < NUM_READERS; i++) { 133 ids[i] = i; 134 if ((r = pthread_create(&tr[i], NULL, reader, &ids[i]))) 135 errc(1, r, "create %d", i); 136 } 137 138 if ((r = pthread_create(&tw, NULL, writer, NULL))) 139 errc(1, r, "create writer"); 140 141 pthread_mutex_lock(&m); 142 while (state != WRITE) 143 pthread_cond_wait(&c, &m); 144 state = WRITE_DONE; 145 pthread_mutex_unlock(&m); 146 pthread_cond_broadcast(&c); 147 148 pthread_join(tw, NULL); 149 150 for (i = 0; i < NUM_READERS; i++) 151 pthread_join(tr[i], NULL); 152 return 0; 153 } 154