I'm actually doing a personal project where I have to make a little program that simulate this behavior :
There is 2 type of people : Villager and Druid (as Asterix/Obelix)
Each VILLAGER is identified by an id (a number unique to the villager). It will fight "nb_fights" time before leaving the battlefield. Before each fight, it must take a serving of magical potion from the pot (if the pot is empty, it must inform the druid and wait until the pot is refilled).
The DRUID will wait to be called by a villager; then it will refill the pot with pot_size servings. When nb_refills have been done, the druid has run out of ingredients and it’s thread must stop.
Everything is given in the parameters (./panoramix <nb_villagers> <pot_size> <nb_fights> <nb_refills>)
Well, actually I did 70% of the project but I have trouble calling the druid to refill the potions.
There is the code for the Villager thread :
void *villager(void *args)
{
int pNb = nbF;
int id = *(int *)args;
printf("Villager %d: Going into battle!\n", id);
while (pNb > 0) {
pthread_mutex_lock(&mpot);
printf("Villager %d: I need a drink... I see %d servings left.\n", id, pot_size);
if (pot_size == 0) {
printf("Villager %d: Hey Pano wake up! We need more potion.\n", id);
sem_wait(&test);
}
pot_size--;
pthread_mutex_unlock(&mpot);
pNb--;
printf("Villager %d: Take that roman scum! Only %d left.\n", id, pNb);
}
printf("Villager %d: I’m going to sleep now.\n", id);
}
WITH pNb = Number of fight (that we decrement)
then there is the Druid thread :
void *druid(void *args)
{
int sizepot = pot_size;
printf("Druid: I'm ready... but sleepy...\n");
while (nb_refills > 0) {
while (pot_size != 0) {
}
sem_wait(&test);
nb_refills--;
printf("Druid: Ah! Yes, yes, I'm awake! Working on it! Beware I can only make %d more refills after this one.\n", nb_refills);
pot_size = sizepot;
sem_post(&test);
}
printf("Druid: I'm out of viscum. I'm going back to... zZz\n");
}
I would like to know how I can "call" the druid when the "pot_size" is empty (=0).
I tried to do it with semaphore in the if condition :
if (pot_size == 0) {
printf("Villager %d: Hey Pano wake up! We need more potion.\n", id);
sem_wait(&test);
}
(wait the druid for filling the pot_size and then continue the program) but I think this is not really good.
EDIT : THE ENTIRE CODE :
#include "struct.h"
sem_t test;
pthread_mutex_t mpot;
pthread_mutex_t fill;
int nbV = 0;
int pot_size = 0;
int nbF = 0;
int nb_refills = 0;
int errorhandler(int ac, char **av)
{
if (ac != 5)
{
printf("USAGE: ./panoramix <nb_villagers> <pot_size> <nb_fights> <nb_refills> \nValues must be > 0.\n");
return (84);
}
if (atoi(av[1]) == 0 || atoi(av[2]) == 0 || atoi(av[3]) == 0 || atoi(av[4]) == 0)
{
printf("USAGE: ./panoramix <nb_villagers> <pot_size> <nb_fights> <nb_refills> \nValues must be > 0.\n");
return (84);
}
return (0);
}
void *druid(void *args)
{
int sizepot = pot_size;
printf("Druid: I'm ready... but sleepy...\n");
while (nb_refills > 0) {
while (pot_size != 0) {
usleep(1000);
}
pthread_mutex_lock(&fill);
nb_refills--;
printf("Druid: Ah! Yes, yes, I'm awake! Working on it! Beware I can only make %d more refills after this one.\n", nb_refills);
pot_size = sizepot;
pthread_mutex_unlock(&fill);
}
printf("Druid: I'm out of viscum. I'm going back to... zZz\n");
}
void *villager(void *args)
{
int pNb = nbF;
int id = *(int *)args;
printf("Villager %d: Going into battle!\n", id);
while (pNb > 0) {
pthread_mutex_lock(&mpot);
printf("Villager %d: I need a drink... I see %d servings left.\n", id, pot_size);
if (pot_size == 0) {
printf("Villager %d: Hey Pano wake up! We need more potion.\n", id);
}
pot_size--;
pthread_mutex_unlock(&mpot);
pNb--;
printf("Villager %d: Take that roman scum! Only %d left.\n", id, pNb);
}
printf("Villager %d: I’m going to sleep now.\n", id);
}
int main(int ac, char **av)
{
if (errorhandler(ac, av) == 84)
return (84);
nbV = atoi(av[1]);
pot_size = atoi(av[2]);
nbF = atoi(av[3]);
nb_refills = atoi(av[4]);
pthread_t th[nbV];
int i;
pthread_mutex_init(&mpot, NULL);
pthread_mutex_init(&fill, NULL);
sem_init(&test, 0, 1);
for (int i = 0; i < nbV; i++) {
int *a = malloc(sizeof(int));
*a = i;
if (pthread_create(&th[i], NULL, &villager, a) != 0) {
perror("Failed to create the Villager\n");
}
}
pthread_create(&th[nbV], NULL, &druid, NULL);
for (int i = 0; i < atoi(av[1]); i++) {
if (pthread_join(th[i], NULL) != 0) {
perror("Failed to launch the Villager\n");
}
}
sem_destroy(&test);
pthread_mutex_destroy(&mpot);
pthread_mutex_destroy(&fill);
return (0);
}