Курсовая

← разместить еще код

Расшаренный код:

#include <stdio.h>
#include <malloc.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>

#include <X11/Xlib.h>
#include <X11/XKBlib.h>

#define X 100
#define Y 50
#define WND_WIDTH 800
#define WND_HEIGHT 600
#define WND_BRD_WIDTH 3

Display *dspl;
int screen;
Window hwnd;
XEvent event;
GC gc;

//Struct of passsenger
typedef struct{
	int id; // Индификатор пассажира
	int bid; // переменная говорящая есть ли у пассажира заявка (1 -да, 0 - нет)
	int currentPlanet; // текущая планета пассажира (от 1 до 4)
	int requestedPlanet; // запрашиваемая планета пассажира (от 1 до 4)
	int inShip; // статус в корабле (1 - да, 0 - нет)
	int idShip; // индификатор корабля
} Passenger;

//Struct of ship
typedef struct{
	int id; // Индификатор корабля
	int x, y; // Текущие координаты корабля
	int countBusyPlaces; // Количество людей в корабле
	int currentPlanet; // Текущая планетаа корабля ( от 1 до 4)
	int course; // Направленеи корабля (0 - влево, 1 - вправо)
	int inPlanet; // индикатор, говорящий что корабль на планете (1-да, 0-нет)
} Ship;

static Passenger* passengers;
static Ship ships[4];
static int countPassenger;

int stars[600][800];

pthread_mutex_t lockA;
pthread_mutex_t enterS[4]; // мьютексы для входа в корабль
pthread_mutex_t exitS[4];	// мьютексы для выхода из корабля


// Потоковая функция пассажиров
void* FuncPassenger(void* data){

	Passenger *human = (Passenger*) data; // Получили данные из функции и преобразовали к нужному виду

	// основной цикл, который не даёт завершиться потоку
	// тут описана логика пассажира
	while(1){

		human -> bid = 0; // зануляем заявку

		// Далее генерируем нужную планету, чтобы она не была равна текущей
			while (human -> requestedPlanet == human -> currentPlanet) {
						 human -> requestedPlanet = 1 + rand () % 4;
			}

			// генерируем заявку на полёт, пока она не буде получена
			while (human -> bid == 0){
				sleep(1);
				if(rand()%30 == 1)	human -> bid = 1;
			}

			sleep(rand()%7 + 3); // Задержка от 3 до 9 сек

			// Цикл, отвечающий за посадку пассажира
			while(1) {
			human -> idShip = -1; // Говорим что мы ни в каком корабле
			pthread_mutex_lock(&enterS[human -> currentPlanet-1]); // Встаём в очередь на вход в корабль
			pthread_mutex_lock(&lockA); // блокируем данные, чтобы другой поток не смог изменить их раньше
			// Перебираем все корабли
			for(int i=0; i<4; i++){
				// Если прилетевший корабль на текущей планете где и пассажира
				// и если он на планете
				// и если количество людей в корабле меньше 5, то пассажир может сесть
				if(	ships[i].currentPlanet == human -> currentPlanet
				&&	ships[i].inPlanet == 1
				&&	ships[i].countBusyPlaces<5){

					ships[i].countBusyPlaces++;	// Увеличиваем количество людей в корабле
					human -> idShip = ships[i].id; // Запоминаем корабль, в котором летим
					human -> inShip = 1;	// Говорим что пасажир сидит в корабле
					break;
				}
			}
			pthread_mutex_unlock(&lockA); // Отпускаем блокировку данных
			if(human -> inShip == 1) break; // делаем проверку условия для выхода из цикла
		}

		// Данный цикл отвечает за высадку пассажира на запрашиваемой планете
		while(1){
		pthread_mutex_lock(&exitS[human -> currentPlanet-1]);	// Встаёт в очередь на высадку на нужной планете
		pthread_mutex_lock(&lockA);	// блокируем данные, чтобы другой поток не смог изменить их раньше
		// Перебираем все корабли
		for(int i=0; i<4; i++){
			// Если id корабля равно id корабля, который запомнил пользователь
			// и если же текущая планета корабля равна запрашиваемой планете пассажира, то
			// пассажир высаживается на данной планете
				if(ships[i].id == human->idShip && ships[i].currentPlanet == human -> requestedPlanet){
					ships[human -> idShip].countBusyPlaces--;	// Количество людей в шаттле уменьшаается на 1
					human -> currentPlanet = human -> requestedPlanet;	// текущей планетой пассажира становится запрашиваемая
					human -> inShip = 0;	// Говорим что пассажир не в корабле
					break;
				}
		}
		pthread_mutex_unlock(&lockA);	// Отпускаем блокировку данных
			if(human -> currentPlanet == human-> requestedPlanet)	break; // делаем проверку условия выхода из цикла
		}

		usleep(50000);
	}
	pthread_exit(0);
}

// Потоковая функция шаттлов
void* FuncShip(void* data){

	Ship *ship = (Ship*) data;	// Получили данные из функции и преобразовали к нужному виду

 int timer = 35000; // данная переменная отвечает за задержку при перемещении шаттла между планетами

 // основной цикл, который не даёт завершиться потоку
 // тут описана логика пассажира
	while(1){

		ship -> inPlanet = 0; // Говорим что корабль не на планете

		// Проверяем крайние планеты, чтобы сменить направление
		if     (ship -> currentPlanet == 1 && ship -> course == 0) ship -> course = 1;
		else if(ship -> currentPlanet == 4 && ship -> course == 1) ship -> course = 0;

// Далее перемещение корабля
		if(ship -> course == 1){
			ship -> y = 310;
			switch (ship -> currentPlanet) {
				case 1:
					ship -> x = 130;
					while(ship -> x <250){ship -> x +=1; usleep(timer);}
					ship -> currentPlanet = 2;
					break;
				case 2:
					ship -> x = 330;
					while(ship -> x <450){ship -> x +=1; usleep(timer);}
					ship -> currentPlanet = 3;
					break;
				case 3:
					ship -> x = 550;
					while(ship -> x <650){ship -> x +=1; usleep(timer);}
					ship -> currentPlanet = 4;
					break;
			}
		}
		else if(ship -> course == 0) {
			ship -> y = 270;
			switch (ship -> currentPlanet) {
				case 2:
					ship -> x = 250;
					while(ship -> x >130){ship -> x -=1; usleep(timer);}
					ship -> currentPlanet = 1;
					break;
				case 3:
					ship -> x = 450;
					while(ship -> x >330){ship -> x -=1; usleep(timer);}
					ship -> currentPlanet = 2;
					break;
				case 4:
					ship -> x = 650;
					while(ship -> x >530){ship -> x -=1; usleep(timer);}
					ship -> currentPlanet = 3;
					break;
			}
		}
		ship -> inPlanet = 1; // говорим что корабль на планете

		pthread_mutex_unlock(&exitS[ship -> currentPlanet-1]); // Сообщаем пассажирам, что можно высаживаться
		pthread_mutex_unlock(&enterS[ship -> currentPlanet-1]); // Сообщаем пассажирам, что можно садиться на корабль

		sleep(rand()%5); // Ожидание от 0 до 4 сек
	}
	pthread_exit(0);
}

// Функция рисования звезды по координатам и размеру scale
void DrawStar(int x, int y, int scale){

	XDrawLine(dspl, hwnd, gc, x, y+scale+rand()%3, x, y-scale-rand()%3);
	XDrawLine(dspl, hwnd, gc, x-scale-rand()%3, y, x+scale+rand()%3, y);

	XDrawLine(dspl, hwnd, gc, x+scale+rand()%3, y-scale-rand()%3, x-scale-rand()%3, y+scale+rand()%3);
	XDrawLine(dspl, hwnd, gc, x-scale-rand()%3, y-scale-rand()%3, x+scale+rand()%3, y+scale+rand()%3);
}

// Инициализация массива звёзд (массива 600x800)
void InitializationBackground(){
	for(int i=0; i<600; i++){
		for(int j=0; j<800; j++){
			if(rand()%700 == 25)	stars[i][j] = 1;
		}
	}
}

// Функция рисования заднего фона (звёзд), по инициализированному массиву stars
void DrawBackground(){
	for(int i=0; i<600; i++){
		for(int j=0; j<800; j++){
			if(stars[i][j] == 1) 	XFillArc(dspl, hwnd, gc, j, i, 2, 2, 360*64, 360*64);
		}
	}
}

// Функция инициализация графического окна
void InitializationDrawWindow(){
	dspl = XOpenDisplay(NULL); //connection to X-server, presents all information about server: version software-buttons code
	if (dspl == NULL) {
	printf("Error XOpenDisplay\n");
	exit(1);
}
	screen = XDefaultScreen(dspl); //returns the number of main screen

	hwnd = XCreateSimpleWindow(dspl, RootWindow(dspl, screen), X, Y,
	WND_WIDTH, WND_HEIGHT, WND_BRD_WIDTH, BlackPixel(dspl, screen),
	BlackPixel(dspl, screen)); //returns handle of window
	if (hwnd == 0) {
	printf("Error XCreateSimpleWindow\n");
	exit(1);
	}

	XSelectInput(dspl, hwnd, ExposureMask | StructureNotifyMask); //Changing sizes of window/keyboard event/mouse event
	XMapWindow(dspl, hwnd); //visible = true
	gc = XDefaultGC(dspl, screen);


	while(1) {
	XEvent event;
	XNextEvent(dspl, &event);
	if (MapNotify == event.type) break;
	}
}

// Основная функция рисования объектов
void Draw(){

	// Счётчики для подсчёта количества людей и коичества заявок на каждой из планет
	int countAldebarana,
			countVega,
			countEarth,
			countSirius;

	// переменный (буферы), используются при выводе текста в графическое окно
	char bufCount[1],
			 countPass[2];

	XGCValues values;	// переменная, отвечающая за визуальное оформление граф. окна
	InitializationBackground(); // Инициализируем задний фон

	// Главный цикл рисования
	while (1) {

			values.foreground = 0xffffff; // Говорим что последующие элементы будут белые
			XChangeGC(dspl, gc, GCForeground, &values); // Применяем изменения

			// рисуем звёзды
			DrawStar(500,500,2+rand()%4);
			DrawStar(250,360,2+rand()%4);
			DrawStar(600,150,2+rand()%4);
			DrawStar(20,450,2+rand()%4);
			DrawStar(110,170,2+rand()%4);
			DrawStar(400,100,2+rand()%4);

			DrawBackground(); // Рисуем задний фон

		//Создаём таблицу
		XDrawLine(dspl, hwnd, gc, 0, 60, 180, 60);
		XDrawLine(dspl, hwnd, gc, 0, 75, 180, 75);
		XDrawLine(dspl, hwnd, gc, 0, 90, 180, 90);
		XDrawLine(dspl, hwnd, gc, 0, 105, 180, 105);
		XDrawLine(dspl, hwnd, gc, 0, 120, 180, 120);

		XDrawLine(dspl, hwnd, gc, 70, 60, 70, 120);
		XDrawLine(dspl, hwnd, gc, 120, 60, 120, 120);
		XDrawLine(dspl, hwnd, gc, 180, 60, 180, 120);

		XDrawString(dspl, hwnd, gc, 20, 50, "Planets", 7);
		XDrawString(dspl, hwnd, gc, 80, 50, "Total", 5);
		XDrawString(dspl, hwnd, gc, 130, 50, "Bids", 4);

		XDrawString(dspl, hwnd, gc, 10, 72, "Earth", 5);
		XDrawString(dspl, hwnd, gc, 10, 87, "Mars", 4);
		XDrawString(dspl, hwnd, gc, 10, 102, "Titan", 5);
		XDrawString(dspl, hwnd, gc, 10, 117, "Europe", 6);


		// зануляем все счётчики
		countAldebarana =0;
		countVega =0;
		countEarth =0;
		countSirius =0;

// Подсчитываем количество заявок на кажой из планет
		for(int i=0; i< countPassenger; i++){
			if(passengers[i].inShip == 0 && passengers[i].bid == 1){
				switch (passengers[i].currentPlanet) {
					case 1:	countAldebarana++; break;
					case 2:	countVega++; break;
					case 3:	countEarth++; break;
					case 4:	countSirius++; break;
				}
			}
		}

// Пишем полученные результаты в таблицу

		sprintf(countPass, "%d", countAldebarana);
		if(countAldebarana < 10) XDrawString(dspl, hwnd, gc, 140, 72, countPass, 1);
		else XDrawString(dspl, hwnd, gc, 140, 72, countPass, 2);

		sprintf(countPass, "%d", countVega);
		if(countVega < 10) XDrawString(dspl, hwnd, gc, 140, 87, countPass, 1);
		else XDrawString(dspl, hwnd, gc, 140, 87, countPass, 2);

		sprintf(countPass, "%d", countEarth);
		if(countEarth < 10) XDrawString(dspl, hwnd, gc, 140, 102, countPass, 1);
		else XDrawString(dspl, hwnd, gc, 140, 102, countPass, 2);

		sprintf(countPass, "%d", countSirius);
		if(countSirius < 10) XDrawString(dspl, hwnd, gc, 140, 117, countPass, 1);
		else XDrawString(dspl, hwnd, gc, 140, 117, countPass, 2);

		// Зануляем счётчики
		countAldebarana =0;
		countVega =0;
		countEarth =0;
		countSirius =0;

// Подсчитываем количество людей на кажой из планет
		for(int i=0; i< countPassenger; i++){
			if(passengers[i].inShip == 0 ){
				switch (passengers[i].currentPlanet) {
					case 1:	countAldebarana++; break;
					case 2:	countVega++; break;
					case 3:	countEarth++; break;
					case 4:	countSirius++; break;
				}
			}
		}

// Пишем полученные результаты в таблицу

		sprintf(countPass, "%d", countAldebarana);
		if(countAldebarana < 10) XDrawString(dspl, hwnd, gc, 90, 72, countPass, 1);
		else XDrawString(dspl, hwnd, gc, 90, 72, countPass, 2);

		sprintf(countPass, "%d", countVega);
		if(countVega < 10) XDrawString(dspl, hwnd, gc, 90, 87, countPass, 1);
		else XDrawString(dspl, hwnd, gc, 90, 87, countPass, 2);

		sprintf(countPass, "%d", countEarth);
		if(countEarth < 10) XDrawString(dspl, hwnd, gc, 90, 102, countPass, 1);
		else XDrawString(dspl, hwnd, gc, 90, 102, countPass, 2);

		sprintf(countPass, "%d", countSirius);
		if(countSirius < 10) XDrawString(dspl, hwnd, gc, 90, 117, countPass, 1);
		else XDrawString(dspl, hwnd, gc, 90, 117, countPass, 2);


		// Рисуем планеты

		values.foreground = 0xff5ef7; // фиолетовый
		XChangeGC(dspl, gc, GCForeground, &values);
		XFillArc(dspl, hwnd, gc, 50, 250, 80, 80, 360*64, 360*64);
		values.foreground = 0x864df7; // синий
		XChangeGC(dspl, gc, GCForeground, &values);
		XFillArc(dspl, hwnd, gc, 250, 250, 80, 80, 360*64, 360*64);
		values.foreground = 0x4df7ab; // изумрудный
		XChangeGC(dspl, gc, GCForeground, &values);
		XFillArc(dspl, hwnd, gc, 450, 250, 80, 80, 360*64, 360*64);
		values.foreground = 0xf7f54d; // жёлтый
		XChangeGC(dspl, gc, GCForeground, &values);
		XFillArc(dspl, hwnd, gc, 650, 250, 80, 80, 360*64, 360*64);

		values.foreground = 000000; // белый
		XChangeGC(dspl, gc, GCForeground, &values);

		// Подписываем планеты
		XDrawString(dspl, hwnd, gc, 75, 300, "Earth", 5);
		XDrawString(dspl, hwnd, gc, 275, 300, "Mars", 4);
		XDrawString(dspl, hwnd, gc, 470, 300, "Titan", 5);
		XDrawString(dspl, hwnd, gc, 670, 300, "Europe", 6);

		values.foreground = 0xffffff; // белый
		XChangeGC(dspl, gc, GCForeground, &values);

		// перебираем все корабли
		for(int i=0; i<3; i++){
			// Если корабль летит, то рисуем корабль
			if(ships[i].inPlanet == 0){
				XDrawRectangle(dspl, hwnd, gc, ships[i].x, ships[i].y, 20, 20);
				sprintf(bufCount, "%d", ships[i].countBusyPlaces);
				XDrawString(dspl, hwnd, gc, ships[i].x+9, ships[i].y+15, bufCount, 1);
				XDrawString(dspl, hwnd, gc, ships[i].x, ships[i].y-5, "id", 2);
				sprintf(bufCount, "%d", ships[i].id);
				XDrawString(dspl, hwnd, gc, ships[i].x+15, ships[i].y-5, bufCount, 1);
		}}
		XFlush(dspl); // Очищаем буфер x-сервера
		XClearWindow(dspl, hwnd);	// Очищаем графическое окно от графических примитивов
		usleep(50000);

		}
}

// Главная функция
int main() {

countPassenger = 20; // Количество тек. пассажиров для данной модели
InitializationDrawWindow(); // Инициализация графического окна

// Выделение памяти для указателей потоков
pthread_t* threadsShips = (pthread_t*) malloc(3 * sizeof(pthread_t));	// Потоки кораблей
pthread_t* threadsPassenger = (pthread_t*) malloc(countPassenger * sizeof(pthread_t)); // Потоки пассажиров

passengers = (Passenger*) malloc(countPassenger * sizeof(Passenger)); // Выделяем память под массив структур типа Passenger

srand(time(0));	// Говорим что числа при rand() повторяться не должны

// Перебираем всех пассажиров и устанавливаем переменным исходные значения
// а также запускаем поток
for(int i=0; i< countPassenger; i++){
	passengers[i].id = i;
	passengers[i].bid = 0;
	passengers[i].inShip = 0;
	passengers[i].currentPlanet = 1 + rand () % 4;
	passengers[i].requestedPlanet = passengers[i].currentPlanet;
	while (passengers[i].requestedPlanet == passengers[i].currentPlanet) {
				 passengers[i].requestedPlanet = 1 + rand () % 4;
	}
	pthread_create(&(threadsPassenger[i]), NULL, FuncPassenger, &passengers[i]);
}


// Перебираем все шаттлы и устанавливаем переменным исходные значения
// а также запускаем поток
for(int i=0; i<3; i++){
	ships[i].id = i;
	ships[i].x = 0;
	ships[i].y = 0;
	ships[i].countBusyPlaces = 0;
	ships[i].currentPlanet = 1 + rand ()%4;
	ships[i].course = 0 + rand () % 2;
	ships[i].inPlanet = 1;
	pthread_create(&(threadsShips[i]), NULL, FuncShip, &ships[i]);
}
	Draw(); // Вызываем функция рисования, в котором определён бесконечный цикл

	return 0;
}