I'm trying to do the following assignment:
You will write a program that creates three threads. These threads access a shared integer, buffer, one at a time. The buffer will initially be set to 0. Each thread should print its thread ID, process ID, and the buffer’s current value in one statement, then increment the buffer by one. Use a mutex to ensure this whole process is not interrupted. Have the threads modify the buffer 15 times. When each thread is done, it should return the number of times it changed the buffer to the main thread.
The output should look something like this:
TID: 3077897072, PID: 30656, Buffer: 0
TID: 3069504368, PID: 30656, Buffer: 1
TID: 3059014512, PID: 30656, Buffer: 2
TID: 3077897072, PID: 30656, Buffer: 3
TID: 3069504368, PID: 30656, Buffer: 4
TID: 3077897072, PID: 30656, Buffer: 5
TID: 3059014512, PID: 30656, Buffer: 6
TID: 3069504368, PID: 30656, Buffer: 7
TID: 3077897072, PID: 30656, Buffer: 8
TID: 3059014512, PID: 30656, Buffer: 9
TID: 3069504368, PID: 30656, Buffer: 10
TID: 3077897072, PID: 30656, Buffer: 11
TID: 3069504368, PID: 30656, Buffer: 12
TID: 3059014512, PID: 30656, Buffer: 13
TID: 3069504368, PID: 30656, Buffer: 14
TID 3077897072 worked on the buffer 5 times
TID 3069504368 worked on the buffer 6 times
TID 3059014512 worked on the buffer 4 times
Total buffer accesses: 15
This is the code (in C) I've written to solve the assignment:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
int buffer = 0;
const int NUM_MODIFICATIONS = 15;
pthread_mutex_t lock;
struct Solution {
unsigned long TID;
int mod;
};
void * thread_function() {
struct Solution *sol = malloc(sizeof *sol);
sol->TID = (unsigned long) pthread_self();
sol->mod = 0;
while(buffer < NUM_MODIFICATIONS) {
pthread_mutex_lock(&lock);
printf("TID: %lu, PID: %d, Buffer: %d\n", sol->TID, getpid(), buffer);
buffer++; sol->mod++;
pthread_mutex_unlock(&lock);
sleep(1);
}
return sol;
}
int main() {
pthread_t t1, t2, t3;
pthread_mutex_init(&lock, NULL);
pthread_create(&t1, NULL, thread_function, NULL);
pthread_create(&t2, NULL, thread_function, NULL);
pthread_create(&t3, NULL, thread_function, NULL);
void * out_void1, * out_void2, * out_void3;
struct Solution *out1, *out2, *out3;
pthread_join(t1, &out_void1);
pthread_join(t2, &out_void2);
pthread_join(t3, &out_void3);
out1 = out_void1;
out2 = out_void2;
out3 = out_void3;
printf("TID %lu worked on the buffer %d times\n", out1->TID, out1->mod);
printf("TID %lu worked on the buffer %d times\n", out2->TID, out2->mod);
printf("TID %lu worked on the buffer %d times\n", out3->TID, out3->mod);
printf("Total buffer accesses: %d\n", out1->mod + out2->mod + out3->mod);
pthread_mutex_destroy(&lock);
}
At first, I didn't include the sleep(1)
instruction, which made the program not work as expected (buffer would go up to 17, not sure why, because I'd say the mutex lock is properly set).
My intuition told me some separation between the threads' executions would maybe solve this, so I added the sleep(1)
instruction after the lock is unlocked. Now, it did work, but now this program always makes each thread work 5 times on the buffer, and I can't get it to work so that some thread works a little more or less than the others.
Any help on how to fix this issues would be greatly appreciated.
The problem is that you access buffer
outside of the exclusive zone created by the mutex.
while(buffer < NUM_MODIFICATIONS) { // XXX WRONG
pthread_mutex_lock(&lock);
printf("TID: %lu, PID: %d, Buffer: %d\n", sol->TID, getpid(), buffer);
buffer++; sol->mod++;
pthread_mutex_unlock(&lock);
}
Fixed:
int done = 0;
while ( !done ) {
pthread_mutex_lock( &lock );
done = buffer >= NUM_MODIFICATIONS;
if ( !done ) {
printf( "TID: %lu, PID: %d, Buffer: %d\n", sol->TID, getpid(), buffer );
buffer++;
sol->mod++;
}
pthread_mutex_unlock( &lock );
}