Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КУРСОВАЯ ПО ТВП.docx
Скачиваний:
40
Добавлен:
11.02.2015
Размер:
143.98 Кб
Скачать

2 Задача о пяти обедающих философах

2.1Постановка задачи

Представим себе парк, по аллеям которого прогуливаются пять философов. В центре парка расположена столовая, в которой накрыт круглый стол. На столе стоил миска со спагетти, пять тарелок и пять вилок. Если философ проголодался, он входит в столовую, занимает свободное место за столом, берет две (обязательное условие!!!) вилки и накладывает на тарелку спагетти. Утолив голод, философ возвращает вилки на стол и покидает столовую.

В случае, если все пять философов одновременно придут в столовую, займут места за столом и возьмут по вилке, система окажется заблокированной, т.к. ни один из философов не сможет приступить к еде.

Требуется организовать систему таким образом, чтобы пять философов не могли одновременно оказаться за столом. Если это произойдет, то система окажется заблокированной.

Рисунок 2.1.1 – Задача о пяти обедающих философах

2.2 Решение задачи

В данной задачи имеются две опасные ситуации: «заговор соседей» и «голодная смерть»:

  • «Заговор соседей» имеет место, когда соседи слева и справа от философа строят козни. Заговорщики поочерёдно забирают вилки то слева, то справа от «жертвы». Такие согласованные действия приводят жертву к вынужденному голоданию, так как он никогда не может воспользоваться обеими вилками;

  • «Голодная смерть» возникает, когда философы одновременно проголодаются и одновременно попытаются взять, например, свою левую вилку. При этом возникает тупиковая ситуация, так как никто из них не может начать есть, не имея второй вилки.

Выполним решение данной задачи при помощи сети Петри. На рисунке.1 представлена сеть Петри, на которой показаны основные действия одного философа, но нужно учитывать, что остальные философы действуют также и при посещении столовой могут одновременно попытаться взять одну и туже вилку. Поэтому необходим мьютекс, который будет организовывать доступ к процессу выбора вилок в порядке очереди. Также каждой вилке поставлен в соответствие мьютекс, который организовывает доступ к этой вилке в порядке очереди.

Рисунок 2.2.1 – Решение задачи «Об обедающих философах» с использованием методологии К.Петри

2.3 Листинг процедур, обеспечивающих решение задачи

/* Главная процедура программы «Философ». Существует еще программа «Table» (или «Стол»), которая запускает процессы с передачей параметров запуска.*/

int main(int argc, char* argv[])

{

BOOL fSuccess;

DWORD cbRead, cbWritten, dwMode;

LPSTR lpszPipename="\\\\.\\pipe\\mynamedpipe";

HANDLE hPipe;

srand(atoi(argv[1]));

/* установка именованного соединения со «столом» (необходимо для передачи текущего состояния философа) */

while (1)

{hPipe=CreateFile(

lpszPipename,

GENERIC_READ |

GENERIC_WRITE,

FILE_SHARE_READ,

NULL,

OPEN_EXISTING,

0,

NULL);

if (hPipe != INVALID_HANDLE_VALUE)

break;

if (GetLastError() != ERROR_PIPE_BUSY) return 1;

if (!WaitNamedPipe(lpszPipename, 20000)) return 1;

}

dwMode=PIPE_READMODE_MESSAGE;

fSuccess=SetNamedPipeHandleState(hPipe,

&dwMode,

NULL,

NULL);

if (!fSuccess)

{printf("Ошибка в функции SetNamedPipeHandleState");

return 1;}

fSuccess=ReadFile(hPipe,

chBuf,

512,

&cbRead,

NULL);

if (!fSuccess)

{printf("Ошибка в функции ReadFile");

return 1 ;}

int ind=atoi(chBuf); //запоминаем идентификатор

AnsiString tmp="";

/*создание мьютексов для вилок*/

HANDLE M[2];

/*чтобы не было двух мьютексов с одинаковыми именами, создатся только пять мьютексов. Для исключения взаимной болкировки необходимо,чтобы были философы которые сначала берут правую вилку и были, которые берут левую.*/

if (ind==1) //если философ первый, то создаем мьбтексы с именами M5 и M1

{tmp="M"+IntToStr(5);

M[0] = CreateMutex(NULL, false, tmp.c_str());

tmp="M"+IntToStr(1);

M[1] = CreateMutex(NULL, false, tmp.c_str());

}

Else

/* «нечетный» философ будет брать сначала вилку справа от себя*/

if (ind%2)

{tmp="M"+IntToStr(ind-1);

M[0] = CreateMutex(NULL, false, tmp.c_str());

tmp="M"+IntToStr(ind);

M[1] = CreateMutex(NULL, false, tmp.c_str());

}

else // «четный» философ будет брать сначала вилку слева от себя

{tmp="M"+IntToStr(ind);

M[0] = CreateMutex(NULL, false, tmp.c_str());

tmp="M"+IntToStr(ind-1);

M[1] = CreateMutex(NULL, false, tmp.c_str()); }

inttimeforeat=random(2000)+8000; //общее время для приема пищи

int period; //время на одноразовый прием пищи

DWORD Result;

do

{period=random(2000)+3000;

ToServer(3, ind, hPipe); //философ хочет есть

do

Result = WaitForSingleObject(M[0], 100); //пытается взять первую вилку

while (Result == WAIT_TIMEOUT); //пока не возьмет

do

Result = WaitForSingleObject(M[1], 100); //вторую

while (Result == WAIT_TIMEOUT); //пока не возьмет

ToServer(2, ind, hPipe); //сообщает, что начал есть

if (period>timeforeat) period=timeforeat; //если время на еду больше, чем общее время

//оставшееся до насыщения, переприсваиваем

timeforeat-=period; //уменьшаем время оставшееся до насыщения

Sleep(period); //ест

ReleaseMutex(M[0]); //кладет вилки

ReleaseMutex(M[1]); //мьютексы свободны

ToServer(1, ind, hPipe); //сообщает, что начал думать

Sleep(random(2000)+3000); //думает

} while (timeforeat>0);

ToServer(0, ind, hPipe); //окончание работы

CloseHandle(hPipe);

return 0;}

Рисунок 3 – Пример работы программы