Skip to content

WaPoco/Philosophers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

79 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Philosophers

This project has been created as part of the 42 curriculum by vpogorel.

Description

Philosophers Diagram

This project is about implementing a solution to the classic philosphers dining problem. We have a few philosophers sitting around a circular table. Between each pair of philosophers lies a spoon. To eat, a philosopher must hold two spoons — one in each hand. In the middle of the table is the shared limited food.

How can we schedule spoon usage so that no philosopher starves?

The key to solving the Dining Philosophers is to ensure two properties simultaneously:

  • No deadlock: the system always makes progress — no philosopher is stuck forever waiting.
  • No starvation: every philosopher who wants to eat will eventually get a turn.

Why this matters

The philosphers dining problem refers to the classical synchronization problem in an operating system and illustrates the issue when mutiple threads or processes access shared resources in memory without coordination.

Without careful design, competing threads can fall into:

  • deadlocks: All threads wait forever for resources held by others.
  • Racecondition: unpredictable behaviour of variables in common

This problem is a well-known synchronization challenge in concurrent programming, used to illustrate how multiple threads can share resources safely without conflicts.

How does it work

Resource‐Hierarchy Strategy

Number the spoons and philosophers from 0 through n – 1 clockwise. Each Philosopher can reach two spoons: on the right or left side.

How do I prevent deadlocks?

In order to avoid deadlocks each philosopher should grap opposite forks.

A even numbered Philosopher should pick up the left spoon first, then the right spoon. A odd numbered Philosopher should pick up the right speen first, then the left spoon. If another philosopher is already holding the right or left spoon, he waits until it is available.

If the number of philosopher is even, the result will be that all even numbered philosophers will eat, then all odd numbered philosophers will eat, and so on. This way, no philosopher wait forever and the system will make progress. If the number of philosopher is odd, then result will be two groups of philosophers one will eat and the other one will wait.

In the following animation you will see 4 philosophers.

4 Philosophers

How do I prevent starvation?

if n even : t_die > 2*t_eat + t_sleep, then all philosphers will survive. For this limit we assume that the a philosopher will have to wait at most one time for the spoon, then he will eat and sleep. So the time that a philosopher will wait is at most 2*t_eat + t_sleep.

if n odd : t_die > 3*t_eat + t_sleep, then all philosphers will survive. For this limit we assume that a philosopher will have to wait at most two times for the spoon, then he will eat and sleep. So the time that a philosopher will wait is at most 3*t_eat + t_sleep.

One another limit for both cases could be t_die > 4 * t_eat + t_sleep.

But the limits can depend on the mutex locking, print delays, CPU scheduling and context switches. The limits could is probably higher than the ones mentioned above and we should add some margin to be sure that all philosphers will survive.

How did I implement the strategy ?

One possible way to implement the solution is by using mutexes and threads from the library thread.h.

A thread is the smallest execution unit which the CPU can process and would represent a philosopher. On the other hand the spoons could be represented by mutexes which are kind of locks. When a philosopher graps a fork no one can get access to the same object.

void	grap_fork(t_philosopher *p, pthread_mutex_t *fork)
{
	pthread_mutex_lock(fork);
	print_message(p, "has taken a fork");
}

void	grap_forks(t_philosopher *p)
{
	if (p->id % 2 == 0)
	{
		grap_fork(p, p->lfork);
		grap_fork(p, p->rfork);
	}
	else
	{
		grap_fork(p, p->rfork);
		grap_fork(p, p->lfork);
	}
}

Another way to improve timing is to delay some philosophers at the start so they begin in a better position.

void	*routine(void *arg)
{
	t_philosopher	*p;

	...
	if (p->id % 2 != 0)
		ft_usleep(p, 100);
	...
	return (NULL);
}

📂 Project Structure

philosophers/
├─ Makefile
├─ README.md
├─ include/
│  └─ philo.h
├─ src/
│  ├─ free.c               // functions to free memory from heap
│  ├─ init.c               // allocates and initializes philos, mutex locks and threads
│  ├─ monitore.c           // monitores all simulation condition(death of philos, starvation) 
│  ├─ routine1.c           // grap forks
│  ├─ routine.c            // philosopher loop eat(), sleep_time(), thinking()
│  ├─ threads.c            // thread create/join
│  ├─ time.c               // time functions
│  └─ utils.c              // allocation, destroy, print message
└─ tests/
   └─ scenarios.sh        // quick runs for common/edge cases
|
└─ picures/
   └─ 0012.jpg

Usage

./Philosophers n t_die t_eat t_sleep must_eat

Arguments

  • n number of philosophers and forks
  • t_die time in ms that past after the last meal. After that duration a philospher will starve to death.
  • t_eat time in ms that a philosopher needs during eating
  • t_sleep time in ms that a philosopher needs during sleeping
  • must_eatnumber of times each philosopher should eat atleast

Output:

time_past | i-philosopher | state of a philosopher(thinking, eating, grabing or sleeping)

Example

./Philosophers 5 400 200 200

Output:

0 0 is thinking
0 0 has taken a fork
0 0 has taken a fork
0 0 is eating
0 1 is thinking
0 1 has taken a fork
0 2 is thinking
0 3 is thinking
200 0 is sleeping
200 3 has taken a fork
200 3 has taken a fork
200 3 is eating
200 1 has taken a fork
200 1 is eating
401 0 is thinking
401 0 died

Tests

Tests We had to test with valgrind tool=helgrind for dataraces and deadlocks.

Instructions

Clone the repo:

git clone https://github.com/WaPoco/Philosophers

Change directory:

cd Philosophers

Create the binary:

make

Clean up at the end:

make fclean

Resources

About

This project implements one classic solution to the Dining Philosophers problem using mutexes and threads. Built as part of the 42 school curriculum.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors