Добрый день! Я нашла программу в интернете, решающую проблему обедающих философов на С++ с помощью MPI. Ниже прикрепляю код:
Код:
/*
Compile:
mpic++ philosophers.cpp -o philosophers
Use:
mpiexec -np 6 philosophers
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <list>
#include <Windows.h>
#include "mpi.h"
void philosopher(int);
void table(int, int);
#define FORK_REQUEST 1
#define FORK_RESPONSE 2
#define FORK_RELEASE 3
int main(int argc, char** argv) {
int myrank, nprocs;
//init MPI
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
//Depending on rank, Philosopher or Table
if (myrank == 0)
{
table(myrank, nprocs);
}
else
{
philosopher(myrank);
}
MPI_Finalize();
return 0;
}
/* Philosopher function - only philosopher processes run this */
void philosopher(int myrank) {
printf("Hello from philosopher %d \n", myrank);
int in_buffer[1];
int out_buffer[1];
MPI_Status stat;
out_buffer[0];
srand(time(NULL) + myrank);
//Philosopher main loop
while (true) {
printf("Philosopher %d is sleeping \n", myrank);
Sleep(rand() % 10); //Sleep
printf("Philosopher %d is waiting to eat \n", myrank);
MPI_Send(out_buffer, 1, MPI_INT, 0, FORK_REQUEST, MPI_COMM_WORLD); //Request forks
MPI_Recv(in_buffer, 1, MPI_INT, 0, FORK_RESPONSE, MPI_COMM_WORLD, &stat); //Wait for response
printf("Philosopher %d is eating \n", myrank);
Sleep(rand() % 10); //Eat
printf("Philosopher %d is done eating \n", myrank);
MPI_Send(out_buffer, 1, MPI_INT, 0, FORK_RELEASE, MPI_COMM_WORLD); //Release forks
}
}
/* Table function - only table process run this */
void table(int myrank, int nprocs) {
printf("Hello from table %d \n", myrank);
int in_buffer[1];
int out_buffer[1];
int philosopher;
MPI_Status stat;
std::list<int> queue;
bool *fork = new bool [nprocs-1];
for (int i = 0; i < nprocs-1; i++) fork[i] = true; //Init all forks as free
//Table main loop
while (true) {
MPI_Recv(in_buffer, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &stat); // Recive next message
philosopher = stat.MPI_SOURCE; //Read source of message
if (stat.MPI_TAG == FORK_REQUEST) { //If Request for forks
printf("Table got philosopher %d fork request\n", philosopher);
if (fork[philosopher % (nprocs - 1)] == true && fork[philosopher - 1] == true) { //If both forks are free
fork[philosopher % (nprocs - 1)] = false; //Set the forks as taken
fork[philosopher - 1] = false;
MPI_Send(out_buffer, 1, MPI_REAL, philosopher, FORK_RESPONSE, MPI_COMM_WORLD); // Send Fork response to the right philosopher
printf("Table sent philosopher %d the forks\n", philosopher);
}
else //If not both forks are free
queue.push_back(philosopher); //Put in wait queue
}
if (stat.MPI_TAG == FORK_RELEASE) { //If Release of forks
fork[philosopher % (nprocs - 1)] = true; //Set forks to free again
fork[philosopher - 1] = true;
printf("Table got philosopher %d fork release\n", philosopher);
if (!queue.empty()) { //If philosopher waiting for forks
for (std::list<int>::iterator it = queue.begin(); it != queue.end(); it++) { //Go through whole list of waiting philosophers
philosopher = *it;
if (fork[philosopher % (nprocs - 1)] == true && fork[philosopher - 1] == true) { //If one of them can get both forks
fork[philosopher % (nprocs - 1)] = false;
fork[philosopher - 1] = false;
MPI_Send(out_buffer, 1, MPI_INT, philosopher, FORK_RESPONSE, MPI_COMM_WORLD); // send Fork response
printf("Table sent philosopher %d the forks\n", philosopher);
it = queue.erase(it); //Remove from wait list
}
}
}
}
}
}
По логике, этот код верный. Но тем не менее он работает некорректно. При компиляции в студии, согласно первому условию if, заходит только в функцию table и выводит из нее hello, тут все в порядке (так как процесс у нас всего один). А вот при запуске через консоль почему-то в функцию table не заходит вообще, и возвращает на нулевом процессе следующую ошибку: -1073740791: process 0 exited without calling finalize. Судя по логам, в таком случае оно в ветвь if где rank==0 вообще не заходит, как будто нулевого процесса и нет вообще (пробовала в if выводить что-нибудь и не вывелось). Но, что странно, если закомментировать выполнение одной из функций, либо table либо philosofer, программа хоть и не завершит свою работу, но если выполнение остановить то она выведет все что надо из обеих функций и нулевой процесс соответственно появляется. Подозреваю, что дело в бесконечных процессах while (true) в функциях, но понятия не имею что можно сделать. Помогите, пожалуйста, а то я уже несколько дней бьюсь над этой проблемой((
Прикрепляю скрин работы программы на 6 процессах (5 философов).