104 lines
3.0 KiB
C
104 lines
3.0 KiB
C
/*
|
|
* trylock.c
|
|
*
|
|
* Demonstrate a simple use of pthread_mutex_trylock. The
|
|
* counter_thread updates a shared counter at intervals, and a
|
|
* monitor_thread occasionally reports the current value of the
|
|
* counter -- but only if the mutex is not already locked by
|
|
* counter_thread.
|
|
*
|
|
* Special notes: On a Solaris system, call thr_setconcurrency()
|
|
* to allow interleaved thread execution, since threads are not
|
|
* timesliced.
|
|
*/
|
|
#include <pthread.h>
|
|
#include "errors.h"
|
|
|
|
#define SPIN 10000000
|
|
|
|
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
long counter;
|
|
time_t end_time;
|
|
|
|
/*
|
|
* Thread start routine that repeatedly locks a mutex and
|
|
* increments a counter.
|
|
*/
|
|
void *counter_thread(void *arg) {
|
|
int status;
|
|
int spin;
|
|
|
|
/*
|
|
* Until end_time, increment the counter each
|
|
* second. Instead of just incrementing the counter, it
|
|
* sleeps for another second with the mutex locked, to give
|
|
* monitor_thread a reasonable chance of running.
|
|
*/
|
|
while (time(NULL) < end_time) {
|
|
status = pthread_mutex_lock(&mutex);
|
|
if (status != 0) err_abort(status, "Lock mutex");
|
|
for (spin = 0; spin < SPIN; spin++) counter++;
|
|
sleep(4);
|
|
status = pthread_mutex_unlock(&mutex);
|
|
if (status != 0) err_abort(status, "Unlock mutex");
|
|
sleep(1);
|
|
}
|
|
printf("Counter is %#lx\n", counter);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Thread start routine to "monitor" the counter. Every 3
|
|
* seconds, try to lock the mutex and read the counter. If the
|
|
* trylock fails, skip this cycle.
|
|
*/
|
|
void *monitor_thread(void *arg) {
|
|
int status;
|
|
int misses = 0;
|
|
|
|
/*
|
|
* Loop until end_time, checking the counter every 3
|
|
* seconds.
|
|
*/
|
|
while (time(NULL) < end_time) {
|
|
sleep(3);
|
|
status = pthread_mutex_trylock(&mutex);
|
|
if (status != EBUSY) {
|
|
if (status != 0) err_abort(status, "Trylock mutex");
|
|
printf("Counter is %ld\n", counter / SPIN);
|
|
status = pthread_mutex_unlock(&mutex);
|
|
if (status != 0) err_abort(status, "Unlock mutex");
|
|
} else
|
|
misses++; /* Count "misses" on the lock */
|
|
}
|
|
printf("Monitor thread missed update %d times.\n", misses);
|
|
return NULL;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int status;
|
|
pthread_t counter_thread_id;
|
|
pthread_t monitor_thread_id;
|
|
|
|
#ifdef sun
|
|
/*
|
|
* On Solaris 2.5, threads are not timesliced. To ensure
|
|
* that our threads can run concurrently, we need to
|
|
* increase the concurrency level to 2.
|
|
*/
|
|
DPRINTF(("Setting concurrency level to 2\n"));
|
|
thr_setconcurrency(2);
|
|
#endif
|
|
|
|
end_time = time(NULL) + 60; /* Run for 1 minute */
|
|
status = pthread_create(&counter_thread_id, NULL, counter_thread, NULL);
|
|
if (status != 0) err_abort(status, "Create counter thread");
|
|
status = pthread_create(&monitor_thread_id, NULL, monitor_thread, NULL);
|
|
if (status != 0) err_abort(status, "Create monitor thread");
|
|
status = pthread_join(counter_thread_id, NULL);
|
|
if (status != 0) err_abort(status, "Join counter thread");
|
|
status = pthread_join(monitor_thread_id, NULL);
|
|
if (status != 0) err_abort(status, "Join monitor thread");
|
|
return 0;
|
|
}
|