Files
learn/Operating Systems/mutex-example.c
T

148 lines
3.7 KiB
C
Raw Normal View History

2024-06-07 22:37:18 -04:00
/* mutex-example.c */
/* multi-threaded example showing multiple threads adding to
* a shared set of global variables
*
* specifically, thread A sums 1 + 2 + ... + a, whereas
* thread B sums 1 + 2 + ... + b
*
* both threads A and B add to global_sum, which should
* then be 1 + 2 + ... + a + 1 + 2 + ... + b
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
/* shared global variables */
int global_a; /* sum: 1 + 2 + ... + a */
int global_b; /* sum: 1 + 2 + ... + b */
int global_sum; /* global_a + global_b */
/* function prototypes for the thread functions */
void * whattodo_for_a( void * arg );
void * whattodo_for_b( void * arg );
void * noise( void * arg );
/* global mutex variables */
pthread_mutex_t mutex_on_global_sum = PTHREAD_MUTEX_INITIALIZER;
int main( int argc, char * argv[] )
{
if ( argc != 3 )
{
fprintf( stderr, "ERROR: Invalid input(s)\n" );
fprintf( stderr, "USAGE: a.out <a> <b>\n" );
return EXIT_FAILURE;
}
int a = atoi( argv[1] );
int b = atoi( argv[2] );
int expected_sum_a = 0;
for ( int i = 1 ; i <= a ; i++ ) expected_sum_a += i;
int expected_sum_b = 0;
for ( int i = 1 ; i <= b ; i++ ) expected_sum_b += i;
int expected_global_sum = expected_sum_a + expected_sum_b;
global_sum = global_a = global_b = 0;
pthread_t tid1, tid2, tid3;
int rc;
rc = pthread_create( &tid1, NULL, whattodo_for_a, &a );
if ( rc != 0 ) { fprintf( stderr, "pthread_create() failed (%d)\n", rc ); return EXIT_FAILURE; }
rc = pthread_create( &tid2, NULL, whattodo_for_b, &b );
if ( rc != 0 ) { fprintf( stderr, "pthread_create() failed (%d)\n", rc ); return EXIT_FAILURE; }
/* TO DO: add a third call to pthread_create() and have that
* child thread call whattodo_for_b(), which then will
* require synchronization on global_b...
*/
rc = pthread_create( &tid3, NULL, noise, NULL );
rc = pthread_join( tid1, NULL );
if ( rc != 0 ) { fprintf( stderr, "pthread_join() failed (%d)\n", rc ); return EXIT_FAILURE; }
rc = pthread_join( tid2, NULL );
if ( rc != 0 ) { fprintf( stderr, "pthread_join() failed (%d)\n", rc ); return EXIT_FAILURE; }
/* no overlap in individual writes/updates to global_a */
printf( "MAIN: global a is %d (expected %d)%s\n", global_a, expected_sum_a,
global_a != expected_sum_a ? " **************" : "" );
/* no overlap in individual writes/updates to global_b */
printf( "MAIN: global b is %d (expected %d)%s\n", global_b, expected_sum_b,
global_b != expected_sum_b ? " **************" : "" );
/* potential overlap in individual writes/updates to global_sum */
printf( "MAIN: global sum is %d (expected %d)%s\n", global_sum, expected_global_sum,
global_sum != expected_global_sum ? " **************" : "" );
return EXIT_SUCCESS;
}
void * whattodo_for_a( void * arg )
{
int a = *(int *)arg;
for ( int i = 1 ; i <= a ; i++ )
{
printf( "Thread A: adding %d to global_a\n", i );
global_a += i;
printf( "Thread A: adding %d to global_sum\n", i );
pthread_mutex_lock( &mutex_on_global_sum );
{
global_sum += i; /* CRITICAL SECTION */
}
pthread_mutex_unlock( &mutex_on_global_sum );
}
return NULL;
}
void * whattodo_for_b( void * arg )
{
int b = *(int *)arg;
for ( int i = 1 ; i <= b ; i++ )
{
printf( "Thread B: adding %d to global_b\n", i );
global_b += i;
printf( "Thread B: adding %d to global_sum\n", i );
pthread_mutex_lock( &mutex_on_global_sum );
{
global_sum += i; /* CRITICAL SECTION */
}
pthread_mutex_unlock( &mutex_on_global_sum );
}
return NULL;
}
void * noise( void * arg )
{
for ( int i = 1 ; i <= 1000 ; i++ )
{
usleep( 100 );
}
return NULL;
}