#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
unsigned long long usecs()
{
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
}
enum status {status_think, status_wait0, status_serve, status_wait1, status_wait2, status_eat, status_dead};
class philosopher
{
public:
philosopher(pthread_mutex_t *left_spoon, pthread_mutex_t *right_spoon, pthread_mutex_t *waiter, timespec *think, timespec *serve, unsigned long long *starve, timespec *eat)
: l(left_spoon), r(right_spoon), w(waiter), time_think(*think), time_eat(*eat), time_serve(*serve), time_starve(*starve)
{
me = status_think;
time_last = usecs();
pthread_create(&id, 0, wrapper, this);
}
~philosopher()
{
pthread_join(id, 0);
}
status stat()
{
if (usecs() - time_last > time_starve && me != status_eat)
return status_dead;
return me;
}
bool isdead()
{
return me == status_dead;
}
private:
static void *wrapper(void *ptr)
{
return static_cast<philosopher *>(ptr)->thread();
}
void *thread()
{
while (true) {
me = status_think;
nanosleep(&time_think, 0);
if (w) {
me = status_wait0;
pthread_mutex_lock(w);
me = status_serve;
nanosleep(&time_serve, 0);
pthread_mutex_unlock(w);
}
me = status_wait1;
pthread_mutex_lock(l);
me = status_wait2;
pthread_mutex_lock(r);
me = status_eat;
if (usecs() - time_last > time_starve) {
me = status_dead;
break;
}
nanosleep(&time_eat, 0);
time_last = usecs();
pthread_mutex_unlock(r);
pthread_mutex_unlock(l);
}
return 0;
}
status me;
pthread_mutex_t *l, *r, *w;
pthread_t id;
timespec time_think, time_eat, time_serve;
unsigned long long time_starve, time_last;
};
class table
{
public:
table(unsigned int number_of_philosophers) : num_p(number_of_philosophers)
{
forks = new pthread_mutex_t[num_p];
for (unsigned int i = 0; i < num_p; ++i)
pthread_mutex_init(&forks[i], 0);
waiter = new pthread_mutex_t; // NULL ohne waiter
pthread_mutex_init(waiter, 0);
p = new philosopher *[num_p];
timespec think, serve, eat;
readtsus("Time to think in us: ", &think);
readtsus("Time to serve in us: ", &serve);
readtsus("Time to eat in us: ", &eat);
unsigned long long starve;
cout << "Time till starved in us: " << flush;
cin >> starve;
for (unsigned int i = 0; i < num_p; ++i)
p[i] = new philosopher(&forks[i], &forks[(i + 1 >= num_p)? 0 : i + 1], waiter, &think, &serve, &starve, &eat);
}
~table()
{
for (unsigned int i = 0; i < num_p; ++i)
delete p[i];
delete[] p;
delete waiter;
delete[] forks;
}
void monitor()
{
timespec t = {0, 250000000};
while (!alldead()) {
cout << " ";
for (unsigned int i = 0; i < num_p; ++i)
printstat(p[i]->stat());
cout << "\r" << flush;
nanosleep(&t, 0);
}
cout << "\nAll dead..." << endl;
}
bool alldead()
{
for (unsigned int i = 0; i < num_p; ++i)
if (!p[i]->isdead())
return false;
return true;
}
private:
void readtsus(const char *promt, struct timespec *t)
{
unsigned long long x;
cout << promt << flush;
cin >> x;
t->tv_nsec = (x % 1000000) * 1000;
t->tv_sec = x / 1000000;
}
void printstat(status s)
{
static char txt[][2] = {"T", "0", "S", "1", "2", "E", "D"};
cout << txt[s];
}
unsigned int num_p;
pthread_mutex_t *forks;
pthread_mutex_t *waiter;
philosopher **p;
};
int main()
{
table t(5);
t.monitor();
}