Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

PTHREADS in C Simulate this: In a coffee shop, customer threads contend for the

ID: 641365 • Letter: P

Question

PTHREADS in C

Simulate this: In a coffee shop, customer threads contend for the two bathrooms available. There is a board, on which two keys can be hanged, one key for each bathroom. When a customer arrives in front of the board, it can take a key and use a bathroom, returning the key later. If no keys are on the board, then the customer goes to sleep. When a customer returns a key, it wakes up a sleeping customer, if any, that can then take the key.

Each customer runs the following pseudo-code:

In the pseudo-code above the "drink coffee" and "use bathroom" operations simply print a message like "Customer X is drinking coffee" and sleep a random number of microseconds between 2,000,000 and 5,000,000 microseconds, using the usleep() standard C function. The point of the exercise is to implement the "get key" and "return key" operations, which should also print messages, as seen in sample output below.

You must ensure that all threads end up gaining access to the bathroom, that no more than two threads are using the bathrooms at the same time, and that two threads can be using the bathrooms at the same time.

Implement a program that takes two integer command-line arguments, N and seed. The program starts N customer threads, each of which produces output. The seed argument is used to seed the random number generator. Use the srand() and rand() standard C functions for seeding and generating random numbers.

Explanation / Answer

coffeeshop.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>


/* Thread argument structure. */
typedef struct Struct {
int id;
int *numKeys;
pthread_mutex_t *key;
pthread_cond_t *cond;
} Struct;


/* Function declaration. */
void *doWork(void *arg);
int getRandom();


/* Execute program. */
int main(int argc, char *argv[]) {
// Check that there are two command-line arguments
if (argc < 3) {
printf("Usage: ./coffeeshop <# of threads> <seed time> ");
exit(0);
}

// Convert arguments to integers
int numThreads = strtol(argv[1], NULL, 10);
int seedTime = strtol(argv[2], NULL, 10);

// Exit if arguments are not positive integers
if (numThreads == 0 || seedTime == 0) {
printf("Usage: ./coffeeshop <# of threads> <seed time> ");
exit(0);
}

// Seed
srand(seedTime);

// Create array of pointers to threads
pthread_t *threadHandler = (pthread_t *) malloc(numThreads * sizeof(threadHandler));

// Create array of pointers to thread argument structures
Struct **threadArg = (Struct **) malloc(numThreads * sizeof(threadArg));

// Create key
pthread_mutex_t *key = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
if (pthread_mutex_init(key, NULL)) {
fprintf(stderr, "Error while creating lock ");
}

// Create key counter
int *numKeys = (int *) malloc(sizeof(int));
*numKeys = 2;

// Create condition
pthread_cond_t *cond = (pthread_cond_t *) malloc(sizeof(pthread_cond_t));
if (pthread_cond_init(cond, NULL)) {
fprintf(stderr, "Error while creating condition variable ");
}

// Create threads
for (int i = 0; i < numThreads; i++) {
// Set up argument structure
Struct *arg = (Struct *) malloc(sizeof(Struct));
arg->id = i;
arg->key = key;
arg->numKeys = numKeys;
arg->cond = cond;

// Place argument structure into handler
threadArg[i] = arg;

// Place thread into thread handler
pthread_t thread;
threadHandler[i] = thread;

// Create thread
if (pthread_create(&threadHandler[i], NULL, doWork, (void *) threadArg[i])) {
fprintf(stderr, "Error while creating thread ");
exit(1);
}
}

// Wait for all threads to return
for (int i = 0; i < numThreads; i++) {
void *return_value;
if (pthread_join(threadHandler[i], &return_value)) {
fprintf(stderr, "Error while waiting for thread ");
exit(1);
}
}

// Free memory
for (int i = 0; i < numThreads; i++) {
free(threadArg[i]);
}
free(threadArg);
free(threadHandler);
free(cond);
free(key);
free(numKeys);

return(0);
}

void *doWork(void *thisarg) {
Struct *arg = (Struct *) thisarg;
// Enter coffee shop
printf("Thread %d enters the coffee shop ", arg->id);
usleep(2000000);

for (int i = 0; i < 10; i++) {
// Drink coffee
printf("Thread %d is drinking coffee ", arg->id);
usleep(getRandom());

// Get key and use bathroom
pthread_mutex_lock(arg->key);
while (*(arg->numKeys) == 0) {
printf("Thread %d is waiting for a key ", arg->id);
pthread_cond_wait(arg->cond, arg->key);
}
*(arg->numKeys) -= 1;
printf("Thread %d got a key ", arg->id);
printf("Thread %d is using the bathroom ", arg->id);
pthread_mutex_unlock(arg->key);

// It takes time to use the bathroom
usleep(getRandom());

// Return key
pthread_mutex_lock(arg->key);
*(arg->numKeys) += 1;
printf("Thread %d put a key back on the board ", arg->id);
pthread_mutex_unlock(arg->key);
pthread_cond_broadcast(arg->cond);
}

// Leave the coffee shop
printf("Thread %d leaves the coffee shop ", arg->id);
}

/* Returns a random integer between 2,000,000 and 10,000,000. */
int getRandom() {
return (2000000 + (rand() % 8000000));
}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Chat Now And Get Quote