90 lines
2.3 KiB
C
90 lines
2.3 KiB
C
|
|
#include <assert.h>
|
||
|
|
#include <inttypes.h>
|
||
|
|
#include <pthread.h>
|
||
|
|
#include <semaphore.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdint.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
|
||
|
|
// Use the struct here for passing arguments to the runner() threads.
|
||
|
|
// All instances of this struct should point to the same pthread_mutex_t
|
||
|
|
// and shared variables.
|
||
|
|
typedef struct args {
|
||
|
|
pthread_mutex_t *lock;
|
||
|
|
int64_t *shared;
|
||
|
|
} arg_t;
|
||
|
|
|
||
|
|
/* Function to run in concurrent threads. The argument passed should be a
|
||
|
|
pointer to a pthread_mutex_t to be used for mutual exclusion. Within the
|
||
|
|
nested for-loop structure, use the mutex to protect the the increments
|
||
|
|
and decrements of the shared variable. To get the timing right for the
|
||
|
|
unit tests, experiment with placing the lock/unlock calls in different
|
||
|
|
places (e.g., around both for-loops, inside the outer one, inside the
|
||
|
|
inner one, etc.) */
|
||
|
|
void *
|
||
|
|
runner (void *arg)
|
||
|
|
{
|
||
|
|
// Retrieve the shared pointer and mutex from the passed struct.
|
||
|
|
arg_t *args = (arg_t *) arg;
|
||
|
|
pthread_mutex_t *lock = args->lock;
|
||
|
|
int64_t *shared = args->shared;
|
||
|
|
|
||
|
|
for (int j = 0; j < 1000000; j++)
|
||
|
|
{
|
||
|
|
pthread_mutex_lock (lock);
|
||
|
|
for (int i = 0; i < 100; i++)
|
||
|
|
{
|
||
|
|
*shared += 1;
|
||
|
|
*shared -= 1;
|
||
|
|
}
|
||
|
|
pthread_mutex_unlock (lock);
|
||
|
|
}
|
||
|
|
|
||
|
|
pthread_exit (NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Simple fork-join routine that creates two threads running the runner()
|
||
|
|
function above. Pass the lock and a pointer to the shared variable to
|
||
|
|
both threads. When both threads complete, return the shared variable,
|
||
|
|
which should have a value of 0.
|
||
|
|
*/
|
||
|
|
int64_t
|
||
|
|
run (void)
|
||
|
|
{
|
||
|
|
int64_t shared = 0;
|
||
|
|
|
||
|
|
pthread_mutex_t lock;
|
||
|
|
if (pthread_mutex_init (&lock, NULL) != 0)
|
||
|
|
{
|
||
|
|
fprintf (stderr, "Failed to initialize mutex\n");
|
||
|
|
return shared;
|
||
|
|
}
|
||
|
|
|
||
|
|
arg_t args;
|
||
|
|
args.lock = &lock;
|
||
|
|
args.shared = &shared;
|
||
|
|
|
||
|
|
pthread_t t1, t2;
|
||
|
|
if (pthread_create (&t1, NULL, runner, &args) != 0)
|
||
|
|
{
|
||
|
|
fprintf (stderr, "Failed to create thread 1\n");
|
||
|
|
pthread_mutex_destroy (&lock);
|
||
|
|
return shared;
|
||
|
|
}
|
||
|
|
if (pthread_create (&t2, NULL, runner, &args) != 0)
|
||
|
|
{
|
||
|
|
fprintf (stderr, "Failed to create thread 2\n");
|
||
|
|
pthread_cancel (t1);
|
||
|
|
pthread_join (t1, NULL);
|
||
|
|
pthread_mutex_destroy (&lock);
|
||
|
|
return shared;
|
||
|
|
}
|
||
|
|
|
||
|
|
pthread_join (t1, NULL);
|
||
|
|
pthread_join (t2, NULL);
|
||
|
|
|
||
|
|
pthread_mutex_destroy (&lock);
|
||
|
|
|
||
|
|
return shared;
|
||
|
|
}
|