ftp.nice.ch/Attic/openStep/implementation/gnustep/sources/alpha-snapshots/pthreads.0.9.2.tgz#/pthreads-0.9.2/locklib/test3.c

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.