
- •Курсовая работа
- •Теоретический вопрос «Виды и свойства алгоритмов»
- •Введение
- •Виды алгоритмов
- •Свойства алгоритмов
- •Дискретность
- •Детерминированность (определенность)
- •Результативность
- •Массовость
- •Допустимость начальных данных
- •Решение задачи Майхилла (о стрелках)
- •Постановка задачи
- •Решение задачи
- •Перечень блоков
- •Функционирование модели
- •Заключение
- •Список использованных источников
Решение задачи Майхилла (о стрелках)
Постановка задачи
Имеется цепь стрелков и офицер. Каждый находящийся в цепи солдат может общаться только со своими соседями справа и слева. Офицер размещается на фланге цепи и может подавать команды только крайнему в цепи стрелку. Общее количество стрелков в цепи каждому из стрелков неизвестно. Общаться каждый из стрелков может только со своими соседями справа и слева. Требуется обеспечить одновременный залп всех стрелков цепи после подачи команды офицером.
Решение задачи
Данная задача решается при помощи автоматной модели поведения стрелка.
На рисунке 1 представлена структурная модель поведения стрелков в задаче Майхилла. Дополнительно к стрелкам в задачу введены блок, моделирующий поведение офицера (он отдает команду стрелкам), и блок, выполняющий протоколирование внутренних состояний объектов, составляющих модель цепи стрелков.
Перечень блоков
Officer – модель офицера;
Rifleman 1, 2, … N – модели стрелков;
WriteStates – блок протокола.
Блоки Officer и WriteStates не обязательные. Первый введен для удобства управления цепью стрелков, второй – для визуализации решения.
Функционирование модели
Объекты модели функционируют параллельно. Время для всех объектов едино и моделируется абстрактным дискретным временем. Офицер, получив команду, передает ее ближайшему стрелку, тот следующему и т.д. Чтобы выполнить команду, стрелки обмениваются между собой информацией. По истечении некоторого периода времени они должны одновременно выполнить команду выстрел. В модели – перейти в одинаковое для всех объектов состояние. При этом все промежуточные состояния объектов на каждом такте протоколируются созданным для этого объектом, который функционирует параллельно остальным объектам, составляющим задачу. [6]
Рисунок 1 – Модель поведения стрелков в задаче Майхилла
Решение задачи на языке высокого уровня С++
Применяя автоматную модель поведения стрелков, выполним решение данной задачи на языке высокого уровня С++.
Прямой счет выполняется таким образом, что первый стрелок, получив команду офицера, при помощи функции ожидании уменьшает счетчик семафора на 1. Далее, через определенный промежуток времени, каждый стрелок в цепи солдатов поступает так же до тех пор, пока счетчик семафора не достигнет своего минимального значения и семафор не выйдет из сигнального состояния. Нахождение семафора в несигнальном состоянии будет сообщать о том, что прямой счет окончен, ведется обратный счет. При окончании обратного счета будет произведен одновременный залп всех стрелков.
Листинг программ сервера («Офицер») и клиента («Стрелок») представлен ниже.
Программа-сервер («Офицер»)
//---------------------------------------------------------------------------
#include <vcl.h>
#include <iostream.h>
#pragma hdrstop
#include "Unit1.h"
#define BUFSIZE 512
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
HANDLE hThread;
HANDLE hProcPipe[5];
LPTSTR lpszPipename = "\\\\.\\pipe\\pipe1001";
HANDLE hPipe;
HANDLE hSemaphoreCount; //дескриптор семафора "Счет"
int SemaphoreMax=5; // максимальный размер счетчика семафора, и его начальное
//значение
int Count=0;
void ConnectShooters(LPVOID); //создание именованного канала для общения с
//клиентом
void ShooterThread(LPVOID); //поток для работы с клиентом
void Shoot(); //произвести выстрел
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
randomize();
for (int i=0; i<5; i++)
{
hProcPipe[i]=NULL;
}
}
//создание именованного канала для общения с клиентом
//---------------------------------------------------------------------------
void ConnectShooters(LPVOID lpvParam)
{
int Number=0;
while (Number<5)
{
bool fConnected;
hPipe = CreateNamedPipe(lpszPipename,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFSIZE,
BUFSIZE,
0,
NULL);
fConnected = ConnectNamedPipe(hPipe, NULL);
if (fConnected)
{
hProcPipe[Number]=hPipe;
//создание потока для работы с клиентом
hThread = CreateThread (NULL,
0,
(LPTHREAD_START_ROUTINE) ShooterThread,
(LPVOID) Number,
0,
NULL);
Number++;
}
else
CloseHandle(hPipe);
}
}
//поток для работы с клиентом
//---------------------------------------------------------------------------
void ShooterThread(LPVOID lpvParam)
{
char chBuf[BUFSIZE];
DWORD cbRead,cbWritten;
bool fSuccess;
int n=(int)lpvParam;
while (1)
{
//считывание ответов клиента из канала
fSuccess = ReadFile(hProcPipe[n],
chBuf,
BUFSIZE,
&cbRead,
NULL);
if (fSuccess)
{
int result=atoi(chBuf);
switch (result)
{
// в случае ответа клиента "1" идет прямой счет
case (1):
Count++;
Form1->StringGrid1->Cells[0][Count-1]= IntToStr(Count)+"-й";
break;
//в случае ответа клиента "2" идет обратный счет
case (2):
Form1->StringGrid1->Cells[1][Count-1]= IntToStr(Count)+"-й команду принял";
Count--;
//при окончании обратного счета производим выстрел
if (Count == 0) Shoot();
break;
default: break;
}
}
else break;
}
CloseHandle(hProcPipe[n]);
hProcPipe[n]=NULL;
}
//выстрел
void Shoot()
{
for (int i = 1; i <= 5; i++)
Form1->StringGrid1->Cells[2][i-1]= "Выстрел";
Form1->Button1->Enabled=true;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
Form1->Button1->Enabled=false;
hThread = CreateThread (NULL,
0,
(LPTHREAD_START_ROUTINE) ConnectShooters,
(LPVOID) 0,
0,
NULL);
if (hThread == NULL) {PrintInfo("Ошибка при создании потока"); return;}
//для каждого стрелка создаем процесс
for (int i=0; i<5; i++)
{
ZeroMemory(&StartupInfo,sizeof (StartupInfo));
StartupInfo.cb=sizeof(StartupInfo);
StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow = SW_HIDE;
//параметр командной строки, определяющий очередность счета
// "стрелков-клиентов"
int ShooterSleep=(i+1)*1000;
AnsiString CommandLine="";
CommandLine="Shooter "+IntToStr(i)+" "+IntToStr(ShooterSleep);
if (!
CreateProcess(NULL,
CommandLine.c_str(), //Указатель на строку,
//определяющую командную строку для выполнения
NULL,
NULL,
false,
0,
NULL,
GetCurrentDir().c_str(), // имя текущего каталога
&StartupInfo, // информация предустановки
&ProcessInfo)) // информация о процессе
{PrintInfo("Не могу создать процесс"); return;}
hProcPipe[i]=ProcessInfo.hProcess;
}
//создаем семафор "Счет"
hSemaphoreCount = CreateSemaphore(NULL, // Адрес структуры TSecurityAttributes
SemaphoreMax, //начальное значение счетчика
SemaphoreMax, //максимальное значение
//счетчика
"SemaphoreCount"); //имя объекта
}
//---------------------------------------------------------------------------
Программа-клиент («Стрелок»)
//---------------------------------------------------------------------------
#include <vcl.h>
#include <iostream.h>
#define BUFSIZE 512
#define N 5
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
LPTSTR lpszPipename="\\\\.\\pipe\\pipe1001";
HANDLE hPipe;
HANDLE hSemaphoreCount; //дескриптор семафора "Счет"
//отправка сообщения на сервер
void MsgToServer(int Message)
{
char chBuf[BUFSIZE];
bool fSuccess;
DWORD cbWritten;
AnsiString S=IntToStr(Message);
wsprintf(chBuf,(const char*)S.c_str(),"/0");
fSuccess =WriteFile(hPipe,
chBuf,
BUFSIZE,
&cbWritten,
NULL);
}
//основная функция
int main(int argc, char* argv[])
{
randomize();
char chBuf[BUFSIZE];
DWORD cbRead, cbWritten, dwMode;
//аргумент командной строки, отвечающий за очередность счета стрелков
int ShooterSleep=atoi(argv[2]);
//получение дескриптора канала
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;
}
Sleep(ShooterSleep);
while (1)
{
//получение дескриптора семафора "Счет"
hSemaphoreCount = OpenSemaphore(SEMAPHORE_ALL_ACCESS, 0, "SemaphoreCount");
//"засыпание" потока для выполнения очередности счета
Sleep(ShooterSleep);
//если семафор в сигнальном состоянии, то идет прямой счет
//иначе выход из цикла, далее - обратный счет
if (WaitForSingleObject(hSemaphoreCount,0) == WAIT_OBJECT_0) MsgToServer(1);
else break;
}
//обратный счет
MsgToServer(2);
//"засыпание" для выполнения очередности обратного счета
Sleep((5000-ShooterSleep)*2);
//закрытие дескрипторов
CloseHandle(hPipe);
CloseHandle(hSemaphoreCount);
return 0;
}
//---------------------------------------------------------------------------