Загрузка данных
#include <windows.h>
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
using namespace std;
const int NUM_SHIPS = 2;
const int SHIP_CAPACITY = 5;
const int MIN_SAIL_TIME = 3000;
const int MAX_SAIL_TIME = 6000;
const int MIN_PATIENCE = 2000;
const int MAX_PATIENCE = 7000;
const int MIN_ARRIVAL_DELAY = 200;
const int MAX_ARRIVAL_DELAY = 800;
const wchar_t* PIPE_NAME = L"\\\\.\\pipe\\PilgrimagePipe";
const wchar_t* CLIENT_EXE = L"ClientPilgrimagePipe.exe";
// ===================== СТРУКТУРЫ ОБМЕНА =====================
struct PilgrimRequest
{
int id;
int patienceMs;
};
struct ServerReply
{
int status; // 0 = FOOT, 1 = SHIP
int shipId;
int placeNumber;
};
// ===================== ГЛОБАЛЬНЫЕ ОБЪЕКТЫ =====================
HANDLE gMutex;
HANDLE gFinishEvent;
// ===================== СТАТИСТИКА =====================
int gTotalPilgrims = 0;
int gByShip = 0;
int gOnFoot = 0;
// ===================== КОРАБЛЬ =====================
struct Ship
{
int id;
int passengers;
bool inPort;
int voyages;
HANDLE fullEvent;
};
Ship gShips[NUM_SHIPS];
// ===================== ДАННЫЕ ДЛЯ ПОТОКА КЛИЕНТА =====================
struct ClientContext
{
HANDLE hPipe;
};
// ===================== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ =====================
void print_time()
{
SYSTEMTIME lt;
GetLocalTime(<);
printf("%02d:%02d:%02d\t", lt.wHour, lt.wMinute, lt.wSecond);
}
int RandomRange(int left, int right)
{
return left + rand() % (right - left + 1);
}
void SafePrint(const string& text)
{
WaitForSingleObject(gMutex, INFINITE);
cout << text << endl;
ReleaseMutex(gMutex);
}
bool LaunchClientProcess(int pilgrimId, int patienceMs)
{
wstring cmd = wstring(CLIENT_EXE) + L" " +
to_wstring(pilgrimId) + L" " +
to_wstring(patienceMs);
vector<wchar_t> cmdBuffer(cmd.begin(), cmd.end());
cmdBuffer.push_back(L'\0');
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
BOOL ok = CreateProcessW(
NULL,
cmdBuffer.data(),
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi
);
if (!ok)
{
print_time();
wcout << L"[ERROR] Не удалось запустить клиента #" << pilgrimId
<< L". Код: " << GetLastError() << endl;
return false;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
}
// ===================== ПОТОК КОРАБЛЯ =====================
DWORD WINAPI ShipThread(LPVOID lpParam)
{
Ship* ship = (Ship*)lpParam;
HANDLE waitHandles[2];
waitHandles[0] = ship->fullEvent;
waitHandles[1] = gFinishEvent;
while (true)
{
WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
WaitForSingleObject(gMutex, INFINITE);
bool finishSignaled = (WaitForSingleObject(gFinishEvent, 0) == WAIT_OBJECT_0);
if (finishSignaled && ship->passengers == 0)
{
ReleaseMutex(gMutex);
print_time();
cout << "[SHIP] Корабль #" << ship->id << " завершает работу.\n";
return 0;
}
if (ship->passengers == 0)
{
ResetEvent(ship->fullEvent);
ReleaseMutex(gMutex);
continue;
}
int currentPassengers = ship->passengers;
ship->inPort = false;
print_time();
if (finishSignaled && currentPassengers < SHIP_CAPACITY)
{
cout << "[SHIP] Корабль #" << ship->id
<< " выполняет последний рейс с "
<< currentPassengers << " паломниками.\n";
}
else
{
cout << "[SHIP] Корабль #" << ship->id
<< " заполнен (" << currentPassengers
<< " паломников) и отплывает.\n";
}
ReleaseMutex(gMutex);
Sleep(RandomRange(MIN_SAIL_TIME, MAX_SAIL_TIME));
WaitForSingleObject(gMutex, INFINITE);
ship->voyages++;
ship->passengers = 0;
ship->inPort = true;
ResetEvent(ship->fullEvent);
print_time();
cout << "[SHIP] Корабль #" << ship->id
<< " вернулся. Рейсов: " << ship->voyages << ".\n";
ReleaseMutex(gMutex);
}
}
// ===================== ПОТОК ОБСЛУЖИВАНИЯ КЛИЕНТА =====================
DWORD WINAPI ClientThread(LPVOID lpParam)
{
ClientContext* ctx = (ClientContext*)lpParam;
HANDLE hPipe = ctx->hPipe;
PilgrimRequest request{};
DWORD cbRead = 0;
BOOL fSuccess = ReadFile(
hPipe,
&request,
sizeof(PilgrimRequest),
&cbRead,
NULL
);
if (!fSuccess || cbRead != sizeof(PilgrimRequest))
{
print_time();
cout << "[ERROR] ReadFile failed. GLE=" << GetLastError() << '\n';
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
delete ctx;
return 1;
}
int pilgrimId = request.id;
int patienceMs = request.patienceMs;
WaitForSingleObject(gMutex, INFINITE);
print_time();
cout << "[CLIENT] Паломник #" << pilgrimId
<< " прибыл в порт. Терпение: "
<< patienceMs << " мс.\n";
ReleaseMutex(gMutex);
DWORD startTime = GetTickCount();
ServerReply reply{};
bool decided = false;
while (!decided)
{
bool boarded = false;
WaitForSingleObject(gMutex, INFINITE);
for (int i = 0; i < NUM_SHIPS; i++)
{
if (gShips[i].inPort && gShips[i].passengers < SHIP_CAPACITY)
{
gShips[i].passengers++;
int placeNumber = gShips[i].passengers;
gByShip++;
boarded = true;
reply.status = 1;
reply.shipId = gShips[i].id;
reply.placeNumber = placeNumber;
print_time();
cout << "[CLIENT] Паломник #" << pilgrimId
<< " сел на корабль #" << gShips[i].id
<< ". Место " << placeNumber
<< "/" << SHIP_CAPACITY << ".\n";
if (gShips[i].passengers == SHIP_CAPACITY)
{
SetEvent(gShips[i].fullEvent);
}
break;
}
}
ReleaseMutex(gMutex);
if (boarded)
{
decided = true;
break;
}
DWORD waited = GetTickCount() - startTime;
if (waited >= (DWORD)patienceMs)
{
WaitForSingleObject(gMutex, INFINITE);
gOnFoot++;
reply.status = 0;
reply.shipId = 0;
reply.placeNumber = 0;
print_time();
cout << "[CLIENT] Паломник #" << pilgrimId
<< " не дождался корабля и ушел пешком.\n";
ReleaseMutex(gMutex);
decided = true;
break;
}
Sleep(100);
}
DWORD cbWritten = 0;
fSuccess = WriteFile(
hPipe,
&reply,
sizeof(ServerReply),
&cbWritten,
NULL
);
if (!fSuccess || cbWritten != sizeof(ServerReply))
{
print_time();
cout << "[ERROR] WriteFile failed. GLE=" << GetLastError() << '\n';
}
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
delete ctx;
return 0;
}
// ===================== MAIN =====================
int main()
{
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
srand(static_cast<unsigned>(time(nullptr)));
gMutex = CreateMutex(NULL, FALSE, NULL);
if (gMutex == NULL)
{
print_time();
cout << "[ERROR] CreateMutex failed. GLE=" << GetLastError() << '\n';
return 1;
}
gFinishEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (gFinishEvent == NULL)
{
print_time();
cout << "[ERROR] CreateEvent(gFinishEvent) failed. GLE=" << GetLastError() << '\n';
CloseHandle(gMutex);
return 1;
}
for (int i = 0; i < NUM_SHIPS; i++)
{
gShips[i].id = i + 1;
gShips[i].passengers = 0;
gShips[i].inPort = true;
gShips[i].voyages = 0;
gShips[i].fullEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (gShips[i].fullEvent == NULL)
{
print_time();
cout << "[ERROR] CreateEvent(ship fullEvent) failed. GLE=" << GetLastError() << '\n';
return 1;
}
}
HANDLE shipThreads[NUM_SHIPS];
for (int i = 0; i < NUM_SHIPS; i++)
{
shipThreads[i] = CreateThread(NULL, 0, ShipThread, &gShips[i], 0, NULL);
if (shipThreads[i] == NULL)
{
print_time();
cout << "[ERROR] CreateThread(ship) failed. GLE=" << GetLastError() << '\n';
return 1;
}
}
int n;
cout << "Введите количество паломников (1..20): ";
cin >> n;
while (cin.fail() || n < 1 || n > 20 || cin.peek() != '\n')
{
cin.clear();
cin.ignore(32768, '\n');
cout << "Некорректный ввод. Введите количество паломников (1..20): ";
cin >> n;
}
gTotalPilgrims = n;
print_time();
cout << "[MESSAGE] Сервер запущен. Запускаю клиентские процессы...\n";
for (int i = 0; i < n; i++)
{
int patience = RandomRange(MIN_PATIENCE, MAX_PATIENCE);
LaunchClientProcess(i + 1, patience);
Sleep(RandomRange(MIN_ARRIVAL_DELAY, MAX_ARRIVAL_DELAY));
}
vector<HANDLE> clientThreads;
for (int i = 0; i < n; i++)
{
HANDLE hPipe = CreateNamedPipeW(
PIPE_NAME,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
n,
sizeof(ServerReply),
sizeof(PilgrimRequest),
5000,
NULL
);
if (hPipe == INVALID_HANDLE_VALUE)
{
print_time();
cout << "[ERROR] CreateNamedPipe failed. GLE=" << GetLastError() << '\n';
continue;
}
BOOL fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (!fConnected)
{
print_time();
cout << "[ERROR] ConnectNamedPipe failed. GLE=" << GetLastError() << '\n';
CloseHandle(hPipe);
continue;
}
ClientContext* ctx = new ClientContext;
ctx->hPipe = hPipe;
HANDLE hClientThread = CreateThread(NULL, 0, ClientThread, ctx, 0, NULL);
if (hClientThread == NULL)
{
print_time();
cout << "[ERROR] CreateThread(client) failed. GLE=" << GetLastError() << '\n';
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
delete ctx;
continue;
}
clientThreads.push_back(hClientThread);
}
if (!clientThreads.empty())
{
WaitForMultipleObjects((DWORD)clientThreads.size(), clientThreads.data(), TRUE, INFINITE);
}
print_time();
cout << "[MESSAGE] Все паломники определились со способом пути.\n";
WaitForSingleObject(gMutex, INFINITE);
for (int i = 0; i < NUM_SHIPS; i++)
{
if (gShips[i].passengers > 0)
{
SetEvent(gShips[i].fullEvent);
}
}
ReleaseMutex(gMutex);
SetEvent(gFinishEvent);
for (int i = 0; i < NUM_SHIPS; i++)
{
SetEvent(gShips[i].fullEvent);
}
WaitForMultipleObjects(NUM_SHIPS, shipThreads, TRUE, INFINITE);
cout << "\n========== ИТОГ ==========\n";
cout << "Всего паломников: " << gTotalPilgrims << endl;
cout << "Добрались кораблем: " << gByShip << endl;
cout << "Ушли пешком: " << gOnFoot << endl;
for (int i = 0; i < NUM_SHIPS; i++)
{
cout << "Корабль #" << gShips[i].id
<< " совершил рейсов: " << gShips[i].voyages << endl;
}
cout << "==========================\n";
for (HANDLE h : clientThreads)
CloseHandle(h);
for (int i = 0; i < NUM_SHIPS; i++)
{
CloseHandle(shipThreads[i]);
CloseHandle(gShips[i].fullEvent);
}
CloseHandle(gFinishEvent);
CloseHandle(gMutex);
return 0;
}