Philosophers
Multi-threaded programming, yay!
# Useful
- cacharle/philosophers_test
- nesvoboda/socrates
- philosophers-visualizer
- Столяров, с. 162
- Рандомная проверка
- rabderus Notion
# To learn
- what are coroutines?
- how fast are mutexes in c when contention?
- how to debug a multi-threaded program
- producer-consumer stuff, though I don’t really know if it’s useful here
# Notes
It’s not necessary to use a Mutex for printf
when you have only one process running, because it’s thread-safe (I think). See - how to use printf
with multiple threads. Also .
usleep
can’t take values more than 10^6
because POSIX. But on most systems it will work anyway. More
here.
# What I’ve learned
Corner cases can bite you in the ass, hacky ways are dangerous.
Rounding error can be a bitch too. Remember time_passed()
.
# Problems
# Deadlocks
If we represent each fork with a mutex, and write an algorithm where each philosophers takes his left fork, then his right fork, all philosophers can take their left forks and get stuck. And die.
Solution - parity. For example, each philosopher with an even index can take his right fork, then his left fork. Or even simpler - the first philosopher takes right fork, then left, while others do the opposite (left, then right).
# Starvation
As forks are not prioritized and philosophers don’t speak with each other, it’s not guaranteed that a fork will be taken by a philosopher who needs it most. And he can die.
A hacky solutuion for this particular task:
For even number of philosophers:
Make a small delay at the start of the simulation for philos with (un)even index. That’s it.
For uneven number of philosophers:
Make a small delay at the start for philos with uneven index, and a delay for the last philo: time_to_eat * 2
plus some delta, like 1 ms. And this delay should also be active for the rest of the philos after their first meal.
# Output control
If one philosopher dies, then others shouldn’t output anything to stdout
. This would be easy to achieve with close(1)
, but close()
is not on the list of allowed functions, so you have to use a mutex for this.
# Functions
pthread_create()
Create a thread. Returns 0 on success.
pthread_join()
Like wait()
for threads. Returns 0 on success.
# Bonus part
Use named semaphores, create with sem_open()
. We’re not allowed to use sem_init()
anyway, which is required for an unnamed semaphore.