Skip to content
Snippets Groups Projects
Commit 89ca7b9b authored by Asgeir.Albretsen's avatar Asgeir.Albretsen
Browse files

Completed the functionality for

ice_cream_station.c and added the explanation.txt file.
parent 388fef26
Branches main
No related tags found
No related merge requests found
{
"files.associations": {
"time.h": "c"
}
}
\ No newline at end of file
My code is based on the skeleton code from the assignment. I have a main function where I
create and join a thread for each worker and customer. Each person has a controller
function with an infinite loop of idling and getting/making ice cream.
To get a little more structure in the code, each person has a struct associated with their
ID. This struct contains basic information like their ID, which thread is associated with
them and a semaphore.
I also set up a queue system as a shared variable. It has all the basic features of a
queue, like enqueueing and dequeueing. All threads interact with the queue. Customers will
add themselves to the queue, while workers check who is at the front and remove Customers
from the queue when they start making ice cream for them. This is a minor quirk you might
have to keep in mind when reviewing my code. This means that customers who are currently
being served, are no longer counted as being in the queue.
The main issue we have to solve in this assignment is synchronization. I gave each thread
their own semaphore to help solve this issue. The workers' semaphore is 0 when they are
sleeping, and 1 when they are working. The customers' semaphore is 0 when they are
relaxing and waiting in the queue, and 1 when their ice cream is being made. This means
the initial value for all of my semaphores is 0, as the workers start out sleeping, and
the customers start out relaxing.
Using this semaphore setup, customers can wake up sleeping workers, and workers can let
customers know their ice cream is done. How this works in practice is that a when a
customer gets to the front of the line, they will check to see if there are any
sleeping workers. If there is, they will ask them for an ice cream by posting the
sleeping workers semaphore. The customer will then wait for their semaphore. When the
worker has finished the ice cream, they post the customers semaphore, letting them know
they can return to the beach and relax.
#include <pthread.h> // pthread
#include <stdio.h> // prinftf
#include <stdlib.h> // random
#include <unistd.h> // sleep
// you might need more header files
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <time.h>
#include <semaphore.h>
void *worker_actions(void *employee_id);
void *customer_actions(void *personal_id);
#define NUM_CUSTOMERS 5
#define NUM_CUSTOMERS 8
#define NUM_WORKERS 2
#define MAX_SLEEP_TIME 10
#define MAX_QUEUE_LENGTH 3
#define QUEUE_ARRAY_LENGTH 5
int main(int argc, char **argv) {
void *workerController(void *employee_id);
void workerIdle(int id);
void workerMakeIcecream(int id);
void *customerController(void *personal_id);
void customerIdle(int id);
void customerGetIcecream(int id);
int queue_peek();
int queue_size();
int queue_dequeue();
bool queue_isEmpty();
bool queue_isFull();
bool queue_contains(int data);
void queue_enqueue(int data);
struct Queue {
int queue[QUEUE_ARRAY_LENGTH];
int front;
int rear;
int itemCount;
};
struct Queue queue;
struct Worker {
int id;
bool busy;
pthread_t thread;
sem_t semaphore;
};
struct Worker workers[NUM_WORKERS];
int personal_ids[NUM_CUSTOMERS], employee_ids[NUM_WORKERS];
struct Customer {
int id;
pthread_t thread;
sem_t semaphore;
};
pthread_t customers[NUM_CUSTOMERS], workers[NUM_WORKERS];
struct Customer customers[NUM_CUSTOMERS];
// create treads
int main(int argc, char **argv) {
// Initialize queue
queue.front = 0;
queue.rear = -1;
queue.itemCount = 0;
// Initialize worker struct array
for (int i = 0; i < NUM_WORKERS; i++) {
employee_ids[i] = i;
pthread_create(&workers[i], NULL, worker_actions, (void *)&employee_ids[i]);
workers[i].id = i;
pthread_create(&workers[i].thread, NULL, workerController, (void *)&workers[i].id);
}
// Initialize customer struct array
for (int i = 0; i < NUM_CUSTOMERS; i++) {
personal_ids[i] = i;
pthread_create(&customers[i], NULL, customer_actions, (void *)&personal_ids[i]);
customers[i].id = i;
pthread_create(&customers[i].thread, NULL, customerController, (void *)&customers[i].id);
}
// join threads
// Join all threads
for (int i = 0; i < NUM_WORKERS; i++) {
pthread_join(workers[i], NULL);
pthread_join(workers[i].thread, NULL);
}
for (int i = 0; i < NUM_CUSTOMERS; i++) {
pthread_join(customers[i], NULL);
pthread_join(customers[i].thread, NULL);
}
return 0;
}
void *worker_actions(void *employee_id) {
// get the id of this employee
void *workerController(void *employee_id) {
int id = *(int *)employee_id;
while (1) {
workerIdle(id);
workerMakeIcecream(id);
}
}
void workerIdle(int id) {
if (queue_isEmpty()) {
printf("Worker %d sleeps\n", id);
}
sem_wait(&workers[id].semaphore);
}
void *customer_actions(void *personal_id) {
// get the id of this customer
void workerMakeIcecream(int id) {
workers[id].busy = true;
float timeNeededToMakeIcecream = rand() % MAX_SLEEP_TIME + 1;
int customerID = queue_peek();
printf("Worker %d makes ice cream for person %d (%f seconds)\n", id, customerID, timeNeededToMakeIcecream);
queue_dequeue();
sleep(timeNeededToMakeIcecream);
printf("Worker %d hands person %d their ice cream\n", id, customerID);
workers[id].busy = false;
sem_post(&customers[customerID].semaphore);
}
void *customerController(void *personal_id) {
int id = *(int *)personal_id;
while (1) {
if (!queue_contains(id)) {
customerIdle(id);
customerGetIcecream(id);
}
}
}
void customerIdle(int id) {
float timeRelaxing = rand() % MAX_SLEEP_TIME + 1;
printf("Person %d relaxes at beach (%f seconds)\n", id, timeRelaxing);
sleep(timeRelaxing);
}
void customerGetIcecream(int id) {
// If queue is too long, the customer will return to the beach
if (queue_size() > MAX_QUEUE_LENGTH) {
printf("Person %d goes to get ice cream, but retuns to the beach as the queue is too long (> %d)\n", id, MAX_QUEUE_LENGTH);
return;
}
printf("Person %d gets in the queue\n", id);
queue_enqueue(id);
/*printf("QUEUE\n");
for (int i = 0; i < QUEUE_ARRAY_LENGTH; i++) {
printf("%d\n", queue.queue[i]);
}*/
// Loop until this customer is at the front of the queue
while (queue_peek() != id) {}
// Loop until a worker is available
while (1) {
for (int i = 0; i < NUM_WORKERS; i++) {
if (!workers[i].busy) {
printf("Person %d asks worker %d for ice cream\n", id, i);
sem_post(&workers[i].semaphore);
sem_wait(&customers[id].semaphore);
return;
}
}
}
}
/*
QUEUE FUNCTIONS UNDER HERE
*/
// Gets the element at the front of the queue
int queue_peek() {
return queue.queue[queue.front];
}
// Get the current amount of elements in the queue
int queue_size() {
return queue.itemCount;
}
// Remove the element at the front of the queue
int queue_dequeue() {
int data = queue.queue[queue.front++];
if(queue.front == QUEUE_ARRAY_LENGTH) {
queue.front = 0;
}
queue.itemCount--;
return data;
}
// Checks if the queue is empty
bool queue_isEmpty() {
return queue.itemCount == 0;
}
// Checks if the queue is full
bool queue_isFull() {
return queue.itemCount == QUEUE_ARRAY_LENGTH;
}
// Checks if the data parameter is in the queue
bool queue_contains(int data) {
if (queue_size() == 0) {
return false;
}
int index = queue.front;
for (int i = 0; i < QUEUE_ARRAY_LENGTH; i++) {
// Return true if parameter is found in the queue
if (queue.queue[index] == data) {
return true;
}
// Return false if we reach the end before finding the parameter
if (index == queue.rear) {
return false;
}
// Loop around the array representation of the queue if we get to the end of the array, otherwise add 1 to the index
if (index == QUEUE_ARRAY_LENGTH) {
index = 0;
} else {
index++;
}
}
return false;
}
// Place an element at the back of the queue
void queue_enqueue(int data) {
// Only insert if queue is not full
if(!queue_isFull()) {
if(queue.rear == QUEUE_ARRAY_LENGTH-1) {
queue.rear = -1;
}
queue.queue[++queue.rear] = data;
queue.itemCount++;
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment