cześć
jako, że zapoznaję się z tematem wielowątkowści pozwolilem sobie napisać klasyczny już problem kolacji filozofów (problem deadlocków i starvation).
wydaje mi się, że to co napisane poniżej jest w OK
ale nie umiem testować deadlocków i thread starvation
bardzo bym prosił o ocenę ewentualne uwagi i wytłumaczenie jak sprawdzać czy kod jest odporny na w/w dolegliwości
próbuję sprawdzać, czy każdy z filozofów robi wszystko (wychodzi na to, że tak, wynik poniżej) i po tym wnioskuję, że nie ma deadlocków ani głodzenia (ale nie wiem czy to co robię ma sens)
P1 eating.: 876
P1 thinking.: 876
P2 eating.: 876
P2 thinking.: 876
P3 eating.: 1016
P3 thinking.: 1016
P4 eating.: 954
P4 thinking.: 954
P5 eating.: 1030
P5 thinking.: 1030
P6 eating.: 1103
P6 thinking.: 1103
z góry dziekuję za pomoc
std::mutex print_mutex;
std::map<std::string, int> all;
struct table
{
std::atomic<bool> ready{ false };
std::vector<std::mutex> forks;
table(int iforks)
:forks(std::move(std::vector<std::mutex>(iforks)))
{
}
};
struct philosopher
{
private:
const std::string name;
table &dinnertable;
int left_fork_id;
int right_fork_id;
std::thread philosopher_thread;
std::mt19937 rng{ std::random_device{}() };
public:
philosopher(const std::string &name, table & table, int left_fork, int right_fork)
: name(name)
, dinnertable(table)
, left_fork_id(left_fork)
, right_fork_id(right_fork)
, philosopher_thread(&philosopher::dinner, this)
{
}
void dinner()
{
while (!dinnertable.ready);
do
{
think();
eat();
} while (dinnertable.ready);
}
void think()
{
static thread_local std::uniform_int_distribution<> wait(1, 10);//generates random number
//std::this_thread::sleep_for(std::chrono::milliseconds(wait(rng) * 50));
print(name + " thinking.");
}
void eat()
{
std::lock(dinnertable.forks[left_fork_id], dinnertable.forks[right_fork_id]);
std::lock_guard<std::mutex> lock_a(dinnertable.forks[left_fork_id], std::adopt_lock);
std::lock_guard<std::mutex> lock_b(dinnertable.forks[right_fork_id], std::adopt_lock);
static thread_local std::uniform_int_distribution<> wait(1, 10);//generates random number
//std::this_thread::sleep_for(std::chrono::milliseconds(wait(rng) * 50));
print(name + " eating.");
}
void print(const std::string &text)
{
std::lock_guard<std::mutex> lock_print(print_mutex);
//std::cout << text << std::endl;
all[text]++;
}
~philosopher()
{
philosopher_thread.join();
}
};
void phdinner()
{
table table(6);
std::vector<std::unique_ptr<philosopher>> philosophers;
philosophers.emplace_back(std::make_unique<philosopher>("P1", table, 0, 1));
philosophers.emplace_back(std::make_unique<philosopher>("P2", table, 1, 2));
philosophers.emplace_back(std::make_unique<philosopher>("P3", table, 2, 3));
philosophers.emplace_back(std::make_unique<philosopher>("P4", table, 3, 4));
philosophers.emplace_back(std::make_unique<philosopher>("P5", table, 4, 5));
philosophers.emplace_back(std::make_unique<philosopher>("P6", table, 5, 0));
table.ready.store(true);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
table.ready.store(false);
}
int main()
{
{
phdinner();
}
for (const auto &item : all)
{
std::cout << item.first << ": " << item.second << std::endl;
}
return 0;
}