Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Критические ресурсы и секции.docx
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
100.37 Кб
Скачать

1.4 Вывод

Использование механизма критических секций часто бывает необходимо при работе с несколькими потоками. Критические интервалы позволяют избегать ситуации, когда два потока одновременно используют критические ресурсы, а значит гарантирует корректность результатов работы потоков. Важно помнить, что критические секции не являются объектами ядра операционной системы, а являются локальными для каждого из процессов, и что для одного и того же потока вход в критическую секцию возможен неоднократно. Рекомендуется не пытаться экономить ресурсы системы на критических секциях. Много сэкономить все равно не получится, а корректная работа потоков при этом гарантироваться не будет.

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

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

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

Существует множество различных формулировок этой задачи, например, в одной из них философы интерпретируются как процессы, а вилки как ресурсы.[3] В зависимости от формулировки возникают соответствующие опасные ситуации.

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

2.2 Сеть Петри

Решение задачи с использованием методологии К.Петри представлено на рисунке 1.

Философ входит в столовую

Берет в руки вилки

Накладывает спагетти

Кладет вилки на стол

Покидает столовую

Рисунок 1 – Сеть Петри

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

Программа состоит из двух частей – клиента и сервера. Каждая программа клиент соответствует одному философу и посылает сообщения на сервер, который представляет собой стол, за которым сидят философы. Ниже представлены листинги процедур программ клиента и сервера.

Листинг программы-клиента.

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

LPTSTR myPipe = "\\\\.\\pipe\\mynamedpipe";

HANDLE hPipe;

int Number;

const char msg[6][50] = {"left the dinning room", "finished to eat", "is eating now", "wants to eat", "is thinking", "came to the table"};

void SendMsg(int message_num)

{

DWORD cbWritten;

int Buffer[2] = {Number, message_num};

WriteFile(hPipe, &Buffer, sizeof(Buffer), &cbWritten, NULL);

}

void start()

{

Form1->Memo1->Clear();

int N = atoi(ParamStr(1).c_str()); // количество философов

Number = atoi(ParamStr(2).c_str()); // номер данного философа

Form1->Caption="Philosopher "+IntToStr(Number);

while (1)

{

hPipe = CreateFile (myPipe,

GENERIC_READ |

GENERIC_WRITE,

FILE_SHARE_READ,

NULL,

OPEN_EXISTING,

0,

NULL);

if (hPipe != INVALID_HANDLE_VALUE) break;

}

for(;;)

{

Form1->Memo1->Lines->Add("Philosopher "+ IntToStr(Number)+" "+msg[5]);

SendMsg(5); // философ подходит к столу

Sleep(random(2001)+3000);

HANDLE myMutex,myCritical;

// номер левого (правого) соседа философа

int LeftNeighbour=(Number + N -1)%N,

RightNeighbour=(Number+1)%N;

AnsiString LeftFork=IntToStr(LeftNeighbour),

RightFork=IntToStr(RightNeighbour),

eat=IntToStr(Number),

Crit="myCritical";

// создаётся мьютекс взаимного исключения входа в критическую оласть

myCritical = CreateMutex(NULL, false, Crit.c_str());

Form1->Memo1->Lines->Add("Philosopher "+ IntToStr(Number)+" "+msg[4]);

SendMsg(4); // философ размышляет

Sleep(random(2001)+3000);

Form1->Memo1->Lines->Add("Philosopher "+ IntToStr(Number)+" "+msg[3]);

SendMsg(3); // философ хочет есть

bool flag=false;

while (!flag)

{

// ожидание входа в критическую область

WaitForSingleObject(myCritical, INFINITE);

HANDLE LeftForkUsed,RightForkUsed;

// проверка состояния левого и правого соседей

LeftForkUsed = OpenMutex(MUTEX_ALL_ACCESS, 0, LeftFork.c_str());

RightForkUsed = OpenMutex(MUTEX_ALL_ACCESS, 0, RightFork.c_str());

if (!LeftForkUsed&&!RightForkUsed) // если соседи не едят

{

flag=true;

myMutex = CreateMutex(NULL, false, eat.c_str());

SendMsg(2); // философ приступает к приёму пищи

Form1->Memo1->Lines->Add("Philosopher "+ IntToStr(Number)+" "+msg[2]);

ReleaseMutex(myCritical); // выход из критической области

}

else

{

ReleaseMutex(myCritical);

CloseHandle(LeftForkUsed);

CloseHandle(RightForkUsed);

}

}

Sleep(random(2001)+3000);

SendMsg(1); // прекращение приёма пищи

Form1->Memo1->Lines->Add("Philosopher "+ IntToStr(Number)+" "+msg[1]);

Form1->Memo1->Lines->Add("Philosopher "+ IntToStr(Number)+" "+msg[0]);

SendMsg(0); //философ покидает столовую

CloseHandle(myMutex);

Sleep(random(2001)+3000);

}

}

void __fastcall TForm1::FormShow(TObject *Sender)

{

CreateThread(0, 0, (LPTHREAD_START_ROUTINE) start,0, 0, 0);

}

Листинг программы-сервера.

#include <vcl.h>

#include <stdio.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

LPTSTR myPipe = "\\\\.\\pipe\\mynamedpipe";

int Count = 5;

int bSize = 255, MaxWaitTime = 0;

const char msg[6][50] = {"left the dinning room", "finished to eat", "is eating now", "wants to eat", "is thinking", "came to the table"};

VOID InstanceThread(LPVOID lpvParam)

{

DWORD cbBytesRead;

BOOL ReadSuc;

HANDLE hPipe = (HANDLE) lpvParam;

int Buffer[2];

while (1)

{

//Считывание запросов клиента из канала

ReadSuc = ReadFile(

hPipe, // дескриптор канала

Buffer, // выходной буфер

sizeof(Buffer), // размер буфера

&cbBytesRead, // сколько байт считывать

NULL); // синхронный ввод/вывод

Form1->Memo1->Lines->Add("Philosopher "+ IntToStr(Buffer[0])+" "+msg[Buffer[1]]);

if (! ReadSuc || cbBytesRead == 0)

break;

}

FlushFileBuffers(hPipe);//сброс содержимого канала

DisconnectNamedPipe(hPipe);//разъединение

CloseHandle(hPipe);//закрытие дескриптора канала

}

void start()

{ Form1->Memo1->Clear();

char PARAMS[100];

for (int i = 0; i < Count; ++i)

{

sprintf(PARAMS, "%d %d", Count, i + 1);

ShellExecute(0, NULL, "Client.exe", PARAMS, NULL, SW_SHOW);

}

DWORD Identifier;

HANDLE hThread, hPipe;

BOOL ConnectSuc;

while (1)

{

hPipe = CreateNamedPipe(

myPipe, // имя канала

PIPE_ACCESS_DUPLEX, // доступ на

//чтение/запись

PIPE_TYPE_MESSAGE | // канал передачи

// сообщений

PIPE_READMODE_MESSAGE | // режим чтения

// сообщений

PIPE_WAIT, // блокирующийся режим

PIPE_UNLIMITED_INSTANCES, // максимальное число

// экземпляров этого канала в системе

bSize, // размер выходного буфера

bSize, // размер входного буфера

MaxWaitTime, // таймаут для клиента

NULL); // атрибуты

//безопасности отсутствуют

ConnectSuc = ConnectNamedPipe(hPipe, NULL) ?

TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

if (ConnectSuc)

{

hThread = CreateThread(

NULL, // Отсутствие атрибутов безопасности

0, // размер стека потока выбрать по умолчанию

(LPTHREAD_START_ROUTINE) InstanceThread,

(LPVOID) hPipe, // параметр потока

0, // не приостановленный

&Identifier); // возврат идентификатора потока

CloseHandle(hThread);

}

else

CloseHandle(hPipe);

}

}

void __fastcall TForm1::Button1Click(TObject *Sender)

{

CreateThread(0, 0, (LPTHREAD_START_ROUTINE) start,0, 0, 0);

}

Результат работы программы представлен на рисунке 2.

Рисунок 2 – Результат работы программы