This is test3.c in view mode; [Download] [Up]
/* * Simple of test of the R/W lock abstraction. * * This example creates a writer thread that periodically adds a node * to an ordered list of integers (ordered from high to low). In addition, * a set of N reader threads read from the list and check it for consistency. */ #include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <utils.h> #include "locks.h" typedef struct NODE { struct NODE *next; long value; } node_t; typedef struct LIST { node_t *first; long elements; pthread_rwlock_t rwlock; } list_t; static list_t values = { NULL, 0 }; static void update_list( long value ) { node_t *prev, *curr, *node = NULL; /* * Insert a node into the list. Traverse the node until a node * of equal or greater value is encountered and insert the new * node at that point. */ node = malloc( sizeof( node_t )); node->next = NULL; node->value = value; if( values.elements == 0 ) { values.first = node; values.elements += 1; return; } prev = curr = values.first; while( curr != NULL ) { if( node->value == curr->value ) { node->next = curr->next; curr->next = node; break; } if( node->value > curr->value ) { node->next = curr; prev->next = node; break; } prev = curr; curr = curr->next; } if( curr == NULL ) prev->next = node; values.elements += 1; } int check_consistency( void ) { node_t *curr; int count = values.elements, consistent = TRUE; curr = values.first; while( curr != NULL ) { count -= 1; if( curr->next != NULL ) { if( curr->value < curr->next->value ) break; } curr = curr->next; } if( count != 0 ) consistent = FALSE; return( consistent ); } static void writer( long *value ) { struct timespec ts = { 0, 200 }; long new_value = *value, count = *value; int status; while( count > 0 ) { status = pthread_rw_lock_exclusive_np( &values.rwlock ); CHECK(status, "pthread_rw_lock_exclusive_np()"); update_list( new_value ); status = pthread_rw_unlock_exclusive_np( &values.rwlock ); CHECK(status, "pthread_rw_unlock_exclusive_np()"); new_value = rand() % *value; ts.tv_nsec = (rand() % 500) + 200; count -= 1; status = pthread_delay_np( &ts ); CHECK(status, "pthread_delay_np()"); } pthread_exit( (void *) SUCCESS ); } static void reader( void ) { int status, state, consistent = TRUE; status = pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &state ); CHECK(status, "pthread_setcancelstate()"); while( 1 ) { status = pthread_rw_lock_shared_np( &values.rwlock ); CHECK(status, "pthread_rw_lock_shared_np()"); consistent = check_consistency(); status = pthread_rw_unlock_shared_np( &values.rwlock ); CHECK(status, "pthread_rw_unlock_shared_np()"); if( !consistent ) fprintf_r( stderr, "values list is corrupted!\n"); pthread_testcancel(); } pthread_exit( (void *) SUCCESS ); } #define READERS (2) #define WRITERS (1) #define NODES (20) static pthread_t wr[WRITERS]; static pthread_t rdr[READERS]; int main( int argc, char *argv[] ) { long value = NODES; int i, status = 0; void *exit_status = &status; struct timespec ts = { 1, 0 }; if( argc == 2 ) value = atol( argv[1] ); status = pthread_rw_init_np( &values.rwlock ); CHECK(status, "pthread_rw_init_np()"); for(i = 0; i < WRITERS; i++ ) { status = create_joinable( &wr[i], (thread_proc_t) writer, &value ); CHECK(status, "pthread_create()"); } for(i = 0; i < READERS; i++ ) { status = create_joinable( &rdr[i], (thread_proc_t) reader, NULL ); CHECK(status, "pthread_create()"); } pthread_delay_np( &ts ); for(i = 0; i < WRITERS; i++ ) { status = pthread_join( wr[i], &exit_status ); CHECK(status, "pthread_join()"); } for(i = 0; i < READERS; i++ ) { status = pthread_cancel( rdr[i] ); status = pthread_join( rdr[i], &exit_status ); CHECK(status, "pthread_join()"); } if( !check_consistency() ) fprintf_r(stderr, "list is corrupted\n"); status = pthread_rw_destroy_np( &values.rwlock ); CHECK(status, "pthread_rw_destroy_np()"); print_system_counters(); return( SUCCESS ); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.