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.