//
//
//
//
// Lab. Calcolo II - Esempio di codice
//
//
//
//
//
//
//
// Example code: std::thread demonstration: the dining philosophers
// (20130913 francesco.prelz@mi.infn.it)
#include
#include
#include
#include
#include
#include
#include
#include
// Work around the fact that the sleep functions aren't included in the
// default build of the GNU libstdc++
#ifndef _GLIBCXX_USE_NANOSLEEP
#define _GLIBCXX_USE_NANOSLEEP
#endif
#include
#include
#include
#include // localtime, strftime
#include "TApplication.h"
#include "TCanvas.h"
#include "TMultiGraph.h"
#include "TGraph.h"
#include "TAxis.h"
std::vector> forks;
std::mutex waiting_list_mutex;
const int course_time_sec = 2;
struct philosopher
{
std::string name;
int right_fork, left_fork;
unsigned int n_courses;
std::shared_ptr thread;
std::vector start_times;
std::vector end_times;
std::shared_ptr wakeup;
void have_meal();
// Object must be callable.
void operator()() {have_meal();}
};
std::list waiting_list;
std::string
time_label()
{
std::chrono::system_clock::time_point lab_time = std::chrono::system_clock::now();
char timelabel[30];
tm ltime;
time_t lab_time_t = std::chrono::system_clock::to_time_t(lab_time);
::localtime_r(&lab_time_t, <ime);
std::ostringstream ret;
if (strftime(timelabel, sizeof(timelabel), "%T", <ime) > 0)
{
int usec = std::chrono::duration_cast(lab_time.time_since_epoch()).count()
- lab_time_t*1000000LL;
ret << timelabel << "." << std::setprecision(6) << usec << ": ";
}
return ret.str();
}
void
philosopher::have_meal()
{
philosopher *p = this;
for (unsigned int i = 1; i <= p->n_courses; )
{
while (!forks[p->right_fork]->try_lock())
{
std::unique_lock wlock(waiting_list_mutex);
waiting_list.push_back(p);
p->wakeup->wait(wlock);
}
std::cout << time_label() << "Philosopher " << p->name
<< " took fork # " << p->right_fork << std::endl;
if (!forks[p->left_fork]->try_lock())
{
forks[p->right_fork]->unlock();
std::cout << time_label() << "Philosopher " << p->name
<< " returned fork # " << p->right_fork << std::endl;
std::unique_lock wlock(waiting_list_mutex);
// Try waking up the first philosopher in line
if (waiting_list.size() > 0)
{
waiting_list.front()->wakeup->notify_one();
waiting_list.pop_front();
}
waiting_list.push_back(p);
p->wakeup->wait(wlock);
continue;
}
std::cout << time_label() << "Philosopher " << p->name
<< " took fork # " << p->left_fork << std::endl;
std::cout << time_label() << "Philosopher " << p->name
<< " enjoying course # " << i << std::endl;
p->start_times.push_back(std::chrono::system_clock::now());
std::this_thread::sleep_for(std::chrono::seconds(course_time_sec));
forks[p->right_fork]->unlock();
forks[p->left_fork]->unlock();
p->end_times.push_back(std::chrono::system_clock::now());
std::cout << time_label() << "Philosopher " << p->name
<< " returned forks # "
<< p->right_fork << " and " << p->left_fork << std::endl;
{
// Try waking up the first two philosophers in line
std::unique_lock wlock(waiting_list_mutex);
if (waiting_list.size() > 1)
{
waiting_list.front()->wakeup->notify_one();
waiting_list.pop_front();
}
if (waiting_list.size() > 0)
{
waiting_list.front()->wakeup->notify_one();
waiting_list.pop_front();
}
#ifndef GREEDY_PHILOSOPHER
bool need_to_wait = false;
// Put ourselves at the back of the waiting list
// unless it's empty (we could be deadlocking ourselves out)
if ((i <= p->n_courses) && (waiting_list.size() > 0))
{
waiting_list.push_back(p);
need_to_wait = true;
}
if (need_to_wait) p->wakeup->wait(wlock);
#endif
}
#ifndef GREEDY_PHILOSOPHER
// Give the other threads a chance to grab our forks
std::this_thread::sleep_for(std::chrono::milliseconds(1));
#endif
i++;
}
std::cout << time_label() << "Philosopher " << p->name
<< " finished meal." << std::endl;
}
int
main (int argc, char *argv[])
{
const unsigned int n_philosophers=6;
philosopher the_philosophers[n_philosophers];
const char *names[n_philosophers] = {"Plato", "Aristotle", "Descartes",
"Kant", "Hegel", "Heidegger"};
forks.resize(n_philosophers);
for (unsigned int i = 0; ijoin();
}
// Build a timechart of what happened
TMultiGraph lines;
for (unsigned int i = 0; i(i+1);
x[0] = static_cast(std::chrono::duration_cast(the_philosophers[i].start_times[j].time_since_epoch()).count()) / 1000000.;
x[1] = static_cast(std::chrono::duration_cast(the_philosophers[i].end_times[j].time_since_epoch()).count()) / 1000000.;
// The TMultiGraph object will take care of deallocating
// heap graphs.
TGraph *new_line = new TGraph(2, x, y);
new_line->SetLineColor(j+2);
new_line->SetLineWidth(20);
lines.Add(new_line, "L");
}
}
TApplication theApp("The Dining Philosophers", &argc, argv);
TCanvas c1("c1","Timeline", 800, 500);
// No axis is found unless the multigraph is drawn once first.
lines.Draw("A");
TAxis *ax = lines.GetXaxis();
if (ax)
{
ax->SetTimeDisplay(1);
ax->SetTimeFormat("%H:%M:%S");
}
lines.Draw("A");
std::cout << "*** Exit the program by selecting Quit from the File menu ***"
<< std::endl;
theApp.Run(kTRUE);
return 0;
}