mirror of
https://github.com/ION606/learn.git
synced 2026-05-14 21:06:56 +00:00
148 lines
3.7 KiB
C
148 lines
3.7 KiB
C
|
|
/* 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;
|
||
|
|
}
|