
- •КУрсовая работа
- •1 Критические секции, интервалы, ресурсы
- •1.1 Введение
- •1.2 Понятие критической секции и интервала
- •1.3 Работа с критическими секциями
- •1.4 Вывод
- •2 Задача об обедающих философах
- •2.1 Постановка задачи
- •2.2 Сеть Петри
- •2.3 Листинг процедур, обеспечивающих решение задачи
- •2.4 Вывод
- •Список используемых источников
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 – Результат работы программы