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.