First we will look at some code from lecture 10:
This is out flawed implementation for incrementing a shared variable.
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static int nthreads = 5, delay = 5, sum = 1;
int parse_args(int argc, char *argv[], int *nthreads, int* delay){
if ((argc != 3) ||
((*nthreads = atoi(argv[1])) == 0) ||
((*delay = atoi(argv[2])) == 0)) {
fprintf (stderr, "Usage: %s nthreads delay\n", argv[0]);
return(-1); }
return(0);
}
void spin(){
int j;
for(j=0; j< delay; j++);
}
void *updater(void *ptr){
int i;
spin(); i = sum;
spin(); i++;
spin(); sum = i;
spin(); pthread_exit(NULL);
}
int main(int argc, char *argv[]){
int i;
if(parse_args(argc, argv, &nthreads, &delay) < 0){
exit(EXIT_FAILURE);
} else {
pthread_t threads[nthreads];
for(i = 0; i < nthreads ; i++)
pthread_create(&threads[i],NULL,updater,NULL);
for(i = 0; i < nthreads ; i++)
pthread_join(threads[i],NULL);
fprintf(stderr, "sum = %d\n", sum);
exit(EXIT_SUCCESS);
}
}
The program should now behave like:
turing.une.edu.au.Solutions> example02b 10 10000000
sum[0] = 2
sum[1] = 2
sum[2] = 2
sum[3] = 2
sum[4] = 3
sum[5] = 3
sum[6] = 3
sum[7] = 4
sum[8] = 4
sum[9] = 3
Now have a look at our less dangerous example from lecture 10:
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static int nthreads = 5, delay = 5, sum = 1;
static pthread_mutex_t sum_lock = PTHREAD_MUTEX_INITIALIZER;
int parse_args(int argc, char *argv[], int *nthreads, int* delay){
if ((argc != 3) ||
((*nthreads = atoi(argv[1])) == 0) ||
((*delay = atoi(argv[2])) == 0)) {
fprintf (stderr, "Usage: %s nthreads delay\n", argv[0]);
return(-1); };
return(0);
}
void spin(){
int j;
for(j=0; j< delay; j++);
}
void *updater(void *ptr){
int i;
spin(); pthread_mutex_lock(&sum_lock);
spin(); i = sum;
spin(); i++;
spin(); sum = i;
spin(); pthread_mutex_unlock(&sum_lock);
spin(); pthread_exit(NULL);
}
int main(int argc, char *argv[]){
int i;
if(parse_args(argc, argv, &nthreads, &delay) < 0){
exit(EXIT_FAILURE);
} else {
pthread_t threads[nthreads];
for(i = 0; i < nthreads ; i++)
pthread_create(&threads[i],NULL,updater,NULL);
for(i = 0; i < nthreads ; i++)
pthread_join(threads[i],NULL);
fprintf(stderr, "sum = %d\n", sum);
exit(EXIT_SUCCESS);
}
}
Run it with similar values to those used when you ran the code from exercise 1. Notice how the results differ?
We are now going to attempt use a mutex to protect the sum array, so that only one thread can access it at once. Then, we want to develop this further by having a separate lock for each slot in the array.
Begin making a copy of your code from exercise 1, calling it example04b.c
Now, declare and initialize a global mutex, called sum_lock, in much the same way that the example from exercise 2 does. Use the mutex to protect the critical section in the updater procedure. Try having the locking and unlocking outside the loop, then try it inside the loop. Now copy it to SlowSafeInc.c, and make the following changes:
turing.une.edu.au.Solutions> SlowSafeInc 10 10000000
sum[0] = 11
sum[1] = 11
sum[2] = 11
sum[3] = 11
sum[4] = 11
sum[5] = 11
sum[6] = 11
sum[7] = 11
sum[8] = 11
sum[9] = 11
Play around with the producer-consumer example from lecture 10 so that you come to understand the problem:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "putNget.h"
#define SUMSIZE 100
static int sum = 0;
void *producer(void * arg1){
int i;
for (i = 1; i <= SUMSIZE; i++)
put_item(i*i);
pthread_exit(NULL);
}
void *consumer(void *arg2){
int i, myitem;
for (i = 1; i <= SUMSIZE; i++) {
get_item(&myitem);
sum += myitem; }
pthread_exit(NULL);
}
int main(void){
pthread_t prodtid, constid;
int i, total = 0;
for (i = 1; i <= SUMSIZE; i++)
total += i*i;
printf("The actual sum should be %d\n", total);
if(pthread_create(&constid, NULL, consumer, NULL)){
perror("Could not create consumer");
exit(EXIT_FAILURE);
}
if(pthread_create(&prodtid, NULL, producer, NULL)){
perror("Could not create producer");
exit(EXIT_FAILURE);
}
pthread_join(prodtid, NULL);
pthread_join(constid, NULL);
printf("The threads produced the sum %d\n", sum);
exit(EXIT_SUCCESS);
}