Главная страница

Программа моделирования управления движением на уличном перекрестке. Курсач Ворнаков 20ВИ1. 1. Анализ требований к программе и постановка задачи 7 Проектирование и разработка программы 8


Скачать 1.8 Mb.
Название1. Анализ требований к программе и постановка задачи 7 Проектирование и разработка программы 8
АнкорПрограмма моделирования управления движением на уличном перекрестке
Дата11.03.2023
Размер1.8 Mb.
Формат файлаdocx
Имя файлаКурсач Ворнаков 20ВИ1.docx
ТипРеферат
#981132





Содержание


Введение 6

1. Анализ требований к программе и постановка задачи 7

2. Проектирование и разработка программы 8

2.1 Очереди сообщений в UNIX как часть System V IPC 8

2.2 Системный вызов msgget(). Создание очереди сообщений или доступ к уже существующей. 9

2.3 Системный вызов msgsnd(). Отправка сообщения в очередь. 10

2.4 Системный вызов msgrcv(). Получение сообщения из очереди. 12

2.5 Системный вызов msgctl(). Функция обработки очереди сообщений. 14

2.6 Проектирование структуры программного обеспечения. 14

3. Кодирование и тестирование программы 16

3.1 Листинг программы 16

3.2 Тестирование программы 21

Заключение 25

Список используемых источников 26



Введение


LINUX – многозадачная и многопользовательская операционная система для образования, бизнеса, индивидуального программирования. LINUX принадлежит к семейству UNIX-подобных операционных систем.

UNIX – одна из самых популярных в мире операционных систем благодаря тому, что ее сопровождает и распространяет большое число компаний. Первоначально она была создана как многозадачная система для миникомпьютеров и мэйнфреймов в середине 70-ых годов, но с тех пор она выросла в одну из наиболее распространенных операционных систем.

Первоначально LINUX создавался Линусом Торвальдсомкак хобби. Его вдохновила операционная система Minix. Дальше LINUX стал разрабатываться группой энтузиастов UNIX. Сегодня LINUX – полноценная операционная система UNIX, способная работать с “X Windows”, TCP/IP, Emacs и прочими пакетами. [1]

Достоинства Linux:

  1. Бесплатность.

  2. Настраиваемость.

  3. Простота установки.

  4. Безопасность.

  5. Нетребовательность к ресурсам.

  6. Драйверы оборудования.

  7. Удобная командная строка.

  8. Удобная установка программ.

  9. Продуманная файловая система.

  10. Удобная система хранения настроек.

На данный момент вокруг Linux сформировалось огромное сообщество программистов, которые постоянно усовершенствуют систему. Они разрабатывают новые версии и разновидности данной ОС, пишут самые разнообразные программы, работающие под Linux. [2]

1. Анализ требований к программе и постановка задачи


Необходимо разработать программу моделирования управления движением на уличном перекрёстке. Движение на каждой из 4-х прилегающих к перекрёстку улиц моделируется отдельным процессом. Процесс имитирует подъезжающие к перекрёстку автомобили случайным образом, интенсивности потоков от процессов различны. В начале работы светофор переключается с равными интервалами. По мере накопления статистики по интенсивностям потоков время переключения светофора изменяется. Передача информации процессу, имитирующему светофор, выполняется через сообщения.

Программно-технические требования:

  1. Операционная система семейства Linux.

  2. Язык программирования C++.



2. Проектирование и разработка программы

2.1 Очереди сообщений в UNIX как часть System V IPC


 Очереди сообщений, как и семафоры, и разделяемая память, являются средством связи с непрямой адресацией, требуют инициализации для организации взаимодействия процессов и специальных действий для освобождения системных ресурсов по окончании взаимодействия. Пространством имен очередей сообщений является то же самое множество значений ключа, генерируемых с помощью функции ftok(). Для выполнения примитивов send и receive, соответствующим системным вызовам в качестве параметра передаются IPC-дескрипторы очередей сообщений, однозначно идентифицирующих их во всей вычислительной системе. [3]

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

  1. В порядке FIFO, независимо от типа сообщения.

  2. В порядке FIFO для сообщений конкретного типа.

  3. Первым выбирается сообщение с минимальным типом, не превышающим некоторого заданного значения, пришедшее раньше других сообщений с тем же типом.

Очереди сообщений, как и другие средства System V IPC, позволяют организовать взаимодействие процессов, не находящихся одновременно в вычислительной системе.

2.2 Системный вызов msgget(). Создание очереди сообщений или доступ к уже существующей.


Системный вызов msgget предназначен для выполнения операции доступа к очереди сообщений и, в случае ее успешного завершения, возвращает дескриптор System V IPC для этой очереди.

int msgget(key_t key, int msgflg);

Параметр key является ключом System V IPC для очереди сообщений, т. е. фактически ее именем из пространства имен System V IPC. В качестве значения этого параметра может быть использовано значение ключа, полученное с помощью функции ftok(), или специальное значение IPC_PRIVATE. Использование значения IPC_PRIVATE всегда приводит к попытке создания новой очереди сообщений с ключом, который не совпадает со значением ключа ни одной из уже существующих очередей и не может быть получен с помощью функции ftok() ни при одной комбинации ее параметров.

Параметр msgflg – флаги – играет роль только при создании новой очереди сообщений и определяет права различных пользователей при доступе к очереди, а также необходимость создания новой очереди и поведение системного вызова при попытке создания. Он является некоторой комбинацией (с помощью операции побитовое или – " | ") следующих предопределенных значений и восьмеричных прав доступа:

  • IPC_CREAT — если очереди для указанного ключа не существует, она должна быть создана;

  • IPC_EXCL — применяется совместно с флагом IPC_CREAT. При совместном их использовании и существовании массива с указанным ключом доступ к очереди не производится и констатируется ошибочная ситуация, при этом переменная errno, описанная в файле , примет значение EEXIST;

  • 0400 — разрешено чтение для пользователя, создавшего очередь;

  • 0200 — разрешена запись для пользователя, создавшего очередь;

  • 0040 — разрешено чтение для группы пользователя, создавшего очередь;

  • 0020 — разрешена запись для группы пользователя, создавшего очередь;

  • 0004 — разрешено чтение для всех остальных пользователей;

  • 0002 — разрешена запись для всех остальных пользователей;

Очередь сообщений имеет ограничение по общему количеству хранимой информации, которое может быть изменено администратором системы. Текущее значение ограничения можно узнать с помощью команды ipcs -l

Возвращаемое значение. Системный вызов возвращает значение дескриптора System V IPC для очереди сообщений при нормальном завершении и значение -1 при возникновении ошибки.

2.3 Системный вызов msgsnd(). Отправка сообщения в очередь.


Системный вызов msgsnd предназначен для помещения сообщения в очередь сообщений.

int msgsnd(int msqid, struct msgbuf *ptr, int length, int flag);

Описание системного вызова. Параметр msqid является дескриптором System V IPC для очереди, в которую отправляется сообщение, т. е. значением, которое вернул системный вызов msgget() при создании очереди или при ее поиске по ключу.

Структура struct msgbuf описана в файле  как

struct msgbuf {

long mtype;

char mtext;

};

Она представляет собой некоторый шаблон структуры сообщения пользователя. Сообщение пользователя – это структура, первый элемент которой обязательно имеет тип long и содержит тип сообщения, а далее следует информативная часть теоретически произвольной длины (практически в Linux она ограничена размером 4080 байт и может быть еще уменьшена системным администратором), содержащая собственно суть сообщения. Например:

struct mymsgbuf {

long mtype;

char mtext[1024];

} mybuf;

При этом информация вовсе не обязана быть текстовой. Например:

struct mymsgbuf {

long mtype;

struct {

int iinfo;

float finfo;

} info;

} mybuf;

Тип сообщения должен быть строго положительным числом. Действительная длина полезной части информации (т. е. информации, расположенной в структуре после типа сообщения) должна быть передана системному вызову в качестве параметра length. Этот параметр может быть равен и 0, если вся полезная информация заключается в самом факте наличия сообщения. Системный вызов копирует сообщение, расположенное по адресу, на который указывает параметр ptr, в очередь сообщений, заданную дескриптором msqid.

Параметр flag может принимать два значения: 0 и IPC_NOWAIT. Если значение флага равно 0, и в очереди не хватает места для того, чтобы поместить сообщение, то системный вызов блокируется до тех пор, пока не освободится место. При значении флага IPC_NOWAIT системный вызов в этой ситуации не блокируется, а констатирует возникновение ошибки с установлением значения переменной errno, описанной в файле , равным EAGAIN.

Возвращаемое значение. Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.

2.4 Системный вызов msgrcv(). Получение сообщения из очереди.


Системный вызов msgrcv предназначен для получения сообщения из очереди сообщений. [4]

int msgrcv(int msqid, struct msgbuf *ptr,

int length, long type, int flag);

Описание системного вызова. Параметр msqid является дескриптором System V IPC для очереди, из которой должно быть получено сообщение, т. е. значением, которое вернул системный вызов msgget() при создании очереди или при ее поиске по ключу.

Параметр type определяет способ выборки сообщения из очереди следующим образом:

Таблица 1 – Способ выборки

Способ выборки

Значение параметра type

В порядке FIFO, независимо от типа сообщения

0

В порядке FIFO для сообщений с типом n

n

Первым выбирается сообщение с минимальным типом, не превышающим значения n, пришедшее ранее всех других сообщений с тем же типом

-n

Структура struct msgbuf описана в файле  как

struct msgbuf {

long mtype;

char mtext;

};

Она представляет собой некоторый шаблон структуры сообщения пользователя. Сообщение пользователя – это структура, первый элемент которой обязательно имеет тип long и содержит тип сообщения, а далее следует информативная часть теоретически произвольной длины (практически в Linux она ограничена размером 4080 байт и может быть еще уменьшена системным администратором), содержащая собственно суть сообщения. Например:

struct mymsgbuf {

long mtype;

char mtext[1024];

} mybuf;

При этом информация вовсе не обязана быть текстовой. Например:

struct mymsgbuf {

long mtype;

struct {

int iinfo;

float finfo;

} info;

} mybuf;

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

В случае удачи системный вызов копирует выбранное сообщение из очереди сообщений по адресу, указанному в параметре ptr, одновременно удаляя его из очереди сообщений.

Параметр flag может принимать значение 0 или быть какой-либо комбинацией флагов IPC_NOWAIT и MSG_NOERROR. Если флаг IPC_NOWAIT не установлен и очередь сообщений пуста или в ней нет сообщений с заказанным типом, то системный вызов блокируется до появления запрошенного сообщения. При установлении флага IPC_NOWAIT системный вызов в этой ситуации не блокируется, а констатирует возникновение ошибки с установлением значения переменной errno, описанной в файле , равным EAGAIN. Если действительная длина полезной части информации в выбранном сообщении превышает значение, указанное в параметре length и флаг MSG_NOERROR не установлен, то выборка сообщения не производится, и фиксируется наличие ошибочной ситуации. Если флаг MSG_NOERROR установлен, то в этом случае ошибки не возникает, а сообщение копируется в сокращенном виде.

Возвращаемое значение. Системный вызов возвращает при нормальном завершении действительную длину полезной части информации, скопированной из очереди сообщений, и значение -1 при возникновении ошибки.

2.5 Системный вызов msgctl(). Функция обработки очереди сообщений.


После завершения процессов, использовавших очередь сообщений, она не вместе со всеми невостребованными сообщениями до тех пор, пока не будет выполнена специальная команда или специальный системный вызов.

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

Возвращаемое значение. При успешном завершении результат равен 0; в случае неудачи возвращается -1. Параметр msqid является дескриптором System V IPC для очереди сообщений, т. е. значением, которое вернул системный вызов msgget() при создании очереди или при ее поиске по ключу. Параметр cmd может принимать начения:

  • IPC_STAT – получить свойства объекта.

  • IPC_SET – изменить свойства объекта.

  • IPC_RMID – удалить объект. [5]

2.6 Проектирование структуры программного обеспечения.


Для представления структуры программного обеспечения была составлена диаграмма развертывания (рисунок 1)



Рисунок 1 – Диаграмма развертывания.

«traffic_lights.cpp» отвечает за работу светофора, находящегося на перекрёстке.

«road1.cpp», «road2.cpp», «road3.cpp», «road4.cpp» представляют из себя 4 дороги данного перекрестка.



3. Кодирование и тестирование программы

3.1 Листинг программы


1) road1.cpp

#include

#include

#include

#include

#include

#include

#include
struct my_msg_st

{

long int my_msg_type;

int some_text;

};

int main (void)

{

int running =1;

struct my_msg_st some_data;

int msgid1;


msgid1 = msgget ((key_t)0001,0666 | IPC_CREAT);

if (msgid1 ==-1)

{

fprintf(stderr, "msgget faild with error: %d\n",errno);

exit(EXIT_FAILURE);

}


while (running)

{ sleep(rand()%6+3);

some_data.my_msg_type = 1;

some_data.some_text = 1;

if (msgsnd (msgid1, &some_data,sizeof(some_data), 0) == -1)

{

fprintf(stderr, "msgsnd faild\n");

exit (EXIT_FAILURE);

}

}

}

2) road2.cpp

#include

#include

#include

#include

#include

#include

#include
struct my_msg_st

{

long int my_msg_type;

int some_text;

};

int main (void)

{

int running =1;

struct my_msg_st some_data;

int msgid2;

msgid2 = msgget ((key_t)0002,0666 | IPC_CREAT);

if (msgid2 ==-1)

{

fprintf(stderr, "msgget faild with error: %d\n",errno);

exit(EXIT_FAILURE);

}

while (running)

{

sleep(rand()%4+1);

some_data.my_msg_type = 1;

some_data.some_text = 2;

if (msgsnd (msgid2, &some_data,sizeof(some_data), 0) == -1)

{

fprintf(stderr, "msgsnd faild\n");

exit (EXIT_FAILURE);

}

}

}
3) road3.cpp
#include

#include

#include

#include

#include

#include

#include
struct my_msg_st

{

long int my_msg_type;

int some_text;

};

int main (void)

{

int running =1;

struct my_msg_st some_data;

int msgid3;

msgid3 = msgget ((key_t)0003,0666 | IPC_CREAT);

if (msgid3 ==-1)

{

fprintf(stderr, "msgget faild with error: %d\n",errno);

exit(EXIT_FAILURE);

}

while (running)

{

sleep(rand()%4+1);

some_data.my_msg_type = 1;

some_data.some_text = 3;

if (msgsnd (msgid3, &some_data,sizeof(some_data), 0) == -1)

{

fprintf(stderr, "msgsnd faild\n");

exit (EXIT_FAILURE);

}

}
4) road4.cpp
#include

#include

#include

#include

#include

#include

#include
struct my_msg_st

{

long int my_msg_type;

int some_text;

};

int main (void)

{

int running =1;

struct my_msg_st some_data;

int msgid4;

msgid4 = msgget ((key_t)0004,0666 | IPC_CREAT);

if (msgid4 ==-1)

{

fprintf(stderr, "msgget faild with error: %d\n",errno);

exit(EXIT_FAILURE);

}

while (running)

{

sleep(rand()%7+1);

some_data.my_msg_type = 1;

some_data.some_text = 4;

if (msgsnd (msgid4, &some_data,sizeof(some_data), 0) == -1)

{

fprintf(stderr, "msgsnd faild\n");

exit (EXIT_FAILURE);

}

}

}
5) traffic_lights.cpp
#include

#include

#include

#include

#include

#include

#include
struct my_msg_st

{

long int my_msg_type;

int some_text;

};
int main (void)

{

int running =1;

int msgid1,msgid2,msgid3,msgid4;

struct my_msg_st some_data;

long int msg_to_receive = 0;

msgid1 = msgget ((key_t)0001,0666 | IPC_CREAT);

msgid2 = msgget ((key_t)0002,0666 | IPC_CREAT);

msgid3 = msgget ((key_t)0003,0666 | IPC_CREAT);

msgid4 = msgget ((key_t)0004,0666 | IPC_CREAT);

if (msgid1 ==-1)

{

fprintf(stderr, "msgget faild with error: %d\n",errno);

exit(EXIT_FAILURE);

}

if (msgid2 ==-1)

{

fprintf(stderr, "msgget faild with error: %d\n",errno);

exit(EXIT_FAILURE);

}

if (msgid3 ==-1)

{

fprintf(stderr, "msgget faild with error: %d\n",errno);

exit(EXIT_FAILURE);

}

if (msgid4 ==-1)

{

fprintf(stderr, "msgget faild with error: %d\n",errno);

exit(EXIT_FAILURE);

}
time_t start,end;

_Bool direction = 1;

start = time(NULL);

int count_car =0;

int t = 15;

while(running)

{

sleep(1);

if (direction)

{

if (msgrcv (msgid1, &some_data, sizeof(some_data),msg_to_receive, IPC_NOWAIT) != -1)

{

printf ("Green light for the road: %d\n ", some_data.some_text);

count_car++;

}

if (msgrcv (msgid3, &some_data, sizeof(some_data),msg_to_receive, IPC_NOWAIT) != -1)

{

printf ("Green light for the road: %d\n ", some_data.some_text);

count_car++;

}

}

else

{

if (msgrcv (msgid2, &some_data, sizeof(some_data),msg_to_receive, IPC_NOWAIT) != -1)

{

printf ("Green light for the road: %d\n ", some_data.some_text);

count_car++;

}

if (msgrcv (msgid4, &some_data, sizeof(some_data),msg_to_receive, IPC_NOWAIT) != -1)

{

printf ("Green light for the road: %d\n ", some_data.some_text);

count_car++;

}

}

end = time(NULL);

if (difftime(end, start) >t)

{ if (direction == 0)

{

if (count_car/4<8) {t++; printf("%d+1\n",t);};

if (count_car/4>8) {t--; printf("%d-1\n",t);};

count_car = 0;

}

direction=!direction;

printf("Change of direction of movement\n");

start = time(NULL);

}

}

if (msgctl(msgid1, IPC_RMID, 0)== -1)

{

fprintf(stderr, "msgctl(IPC_RMID) failed\n");

exit (EXIT_FAILURE);

}

if (msgctl(msgid2, IPC_RMID, 0)== -1)

{

fprintf(stderr, "msgctl(IPC_RMID) failed\n");

exit (EXIT_FAILURE);

}

if (msgctl(msgid3, IPC_RMID, 0)== -1)

{

fprintf(stderr, "msgctl(IPC_RMID) failed\n");

exit (EXIT_FAILURE);

}

if (msgctl(msgid4, IPC_RMID, 0)== -1)

{

fprintf(stderr, "msgctl(IPC_RMID) failed\n");

exit (EXIT_FAILURE);

}

exit(EXIT_SUCCESS);

}



3.2 Тестирование программы


Запуск программы.

Для того что бы запустить программу, надо в системе Linux открыть 5 терминалов и прописать код для запуска дорог и светофора.

В первом терминале надо запустить команды для компиляции 1 дороги:

g++ Wall –o road1 road1.cpp

./ road1

Во втором терминале надо запустить команды для компиляции 2 дороги:

g++ -Wall –o road2 road2.cpp

./ road2

В третьем терминале надо запустить команды для компиляции 3 дороги:

g++ -Wall –o road3 road3.cpp

./ road3

В четвертом терминале надо запустить команды для компиляции 4 дороги:

g++ -Wall –o road4 road4.cpp

./ road4

В пятом терминале надо запустить команды для компиляции светофора: g++ -Wall –o traffic_lights traffic_lights.cpp

./ traffic_lights

Программа запустилась. Чтобы завершить работу программы необходимо нажать сочетание клавиш Ctrl+C.

Выполненная программа представлена на рисунках 2 - 6.



Рисунок 2 – Запуск программы.



Рисунок 3 – Работа программы.



Рисунок 4 – Работа программы.



Рисунок 5 – Работа программы.



Рисунок 6 – Работа программы.

Заключение


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


Список используемых источников


  1. Гордеев А. В. Г68 Операционные системы: Учебник для вузов. 2-е изд. — СПб.: Питер, 2007. — 416 с.: ил.

  2. Операционные системы семейства Linux / URL: http://bourabai.kz/os/linux.htm Дата обращения: 08.12.2021

  3. НОУ ИНТУИТ Очереди сообщений в UNIX / URL: https://intuit.ru/studies/courses/2249/52/lecture/1560 Дата обращения: 08.12.2021

  4. Робачевский А. М. Операционная система UNIX®. % СПб.: 2002. % 528 ил.

  5. System V IPC / URL: https://parallel.uran.ru/book/export/html/505 Дата обращения: 08.12.2021



написать администратору сайта