Добавил:
Факультет ИКСС, группа ИКВТ-61 Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
LAB / WORK_10 / WORK_10 / лаб_раб_10.docx
Скачиваний:
34
Добавлен:
20.02.2019
Размер:
203.19 Кб
Скачать

ФЕДЕРАЛЬНОЕ АГЕНТСТВО СВЯЗИ

ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ

«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ. ПРОФ. М.А. БОНЧ-БРУЕВИЧА»

(СПбГУТ)

Кафедра программной инженерии и вычислительной техники

Отчёт

по лабораторной работе №10 на тему: «Моделирование систем»

по дисциплине «Операционные системы»

Выполнил: студент группы ИКВТ-61, UКозырев А.Б.

« » 2019 г. ___________/А.Б. Козырев/

Принял: __к.т.н. Дагаев А.В.

« » 2019 г. ___________/_А.В. Дагаев/

Задание: разработать приложение, моделирующее систему или стратегию работы системы (напр. стратегия: обслуживания процессов в ОС, обслуживания системы, замещения страниц в ОП, обслуживание заявок на выборку данных HD; моделирование системы массового обслуживания и др.)

QThreads и QSemaphore для “производителя и потребителя”.

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

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

Семафоры позволяют иметь более высокий уровень параллелизма, чем мьютексы. Если бы доступ к буферу был защищен QMutex, то поток потребителя не смог бы получить доступ к буферу в то же время, что и поток производителя. Тем не менее, нет ничего плохого в том, что оба потока работают над разными частями буфера одновременно.

Программа состоит в основном из трех классов: Producer, Consumer и класс QDialog. Оба наследуются от QThread. Круговой буфер, используемый для связи между этими двумя классами и семафорамы, которые его защищают, являются глобальными переменными.

Глобальные переменные

Использование семафоров гарантирует, что производитель никогда не опережает потребителя больше, чем байты BufferSize, и что потребитель никогда не читает данные, которые производитель еще не сгенерировал. Другими словами, мы используем QSemaphore для управления доступом к циклическому буферу, совместно используемому потоком производителя и потоком потребителя.

Для достижения цели мы используем глобальные переменные:

const int DataSize = 100000;

const int BufferSize = 8192;

char buffer[BufferSize];

QSemaphore freeBytes(BufferSize);

QSemaphore usedBytes;

DataSize - это объем данных, которые сгенерирует производитель. Чтобы сделать пример как можно более простым, мы сделаем его постоянным. BufferSize - размер кольцевого буфера. Это меньше, чем DataSize, что означает, что в какой-то момент производитель достигнет конца буфера и перезапустится с самого начала.

Чтобы синхронизировать производителя и потребителя, нам нужны два семафора. Семафор freeBytes контролирует «свободную» область буфера (область, которую производитель еще не заполнил данными или которую потребитель уже прочитал). Семафор usedBytes управляет «используемой» областью буфера (область, заполненная производителем, но которую потребитель еще не прочитал).

Семафор freeBytes инициализируется с помощью BufferSize, потому что изначально весь буфер пуст. Семафор usedBytes инициализируется значением 0 (значение по умолчанию, если оно не указано).

Класс Producer

Класс производителя выглядит так:

#include "producer.h"

#include "common.h"

#include <QDebug>

Producer::Producer(QObject *parent) :

QThread(parent)

{

}

void Producer::run()

{

qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));

for (int i = 0; i < DataSize; ++i) {

freeBytes.acquire();

buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];

usedBytes.release();

if(i % 20 == 0)

emit bufferFillCountChanged(usedBytes.available());

emit producerCountChanged(i);

}

}

Производитель генерирует байты данных DataSize. Прежде чем записать байт в циклический буфер, он должен получить «свободный» байт, используя семафор freeBytes. Вызов QSemaphore :: acquire () может блокироваться, если потребитель не поспевает за производителем.

В конце производитель выпускает байт, используя семафор usedBytes. «Свободный» байт был успешно преобразован в «использованный» байт, готовый для чтения потребителем.

UsedBytes.available () предназначен для пользовательского интерфейса. Возвращает доступные байты для потребителя.

Этот класс испускает два сигнала: один для количества произведенных байтов и уровень байтов, доступных для потребления.

Класс Consumer

Код почти симметричен классу Producer, за исключением того, что на этот раз мы получаем «используемый» байт и освобождаем «свободный» байт вместо противоположного.

#include "consumer.h"

#include "common.h"

Consumer::Consumer(QObject *parent) :

QThread(parent)

{

}

void Consumer::run()

{

for (int i = 0; i < DataSize; ++i) {

usedBytes.acquire();

fprintf(stderr, "%c", buffer[i % BufferSize]);

freeBytes.release();

emit bufferFillCountChanged(usedBytes.available());

emit consumerCountChanged(i);

}

fprintf(stderr, "\n");

}

Класс Dialog

Когда программа запускает QDialog, в конструкторе создаются два новых объекта QThread. Затем, когда нажимается кнопка «Пуск», два потока вызывают start ().

#include "conproddialog.h"

#include "ui_conproddialog.h"

#include "myConstants.h"

// BufferSize: maximum bytes that can be stored

char buffer[BufferSize];

QSemaphore freeBytes(BufferSize);

QSemaphore usedBytes;

ConProdDialog::ConProdDialog(QWidget *parent) :

QDialog(parent),

ui(new Ui::ConProdDialog)

{

ui->setupUi(this);

// progress bar range setup

ui->producerProgressBar->setRange(0, DataSize);

ui->consumerProgressBar->setRange(0, DataSize);

ui->bufferProgressBar->setRange(0, BufferSize);

// make two threads

mProducer = new Producer(this);

mConsumer = new Consumer(this);

// connect signal/slot for the buffer progress bar

connect(mConsumer, SIGNAL(bufferFillCountChanged(int)),

this, SLOT(onBufferValueChanged(int)));

connect(mProducer, SIGNAL(bufferFillCountChanged(int)),

this, SLOT(onBufferValueChanged(int)));

// connect signal/slot for consumer/producer progress bar

connect(mConsumer, SIGNAL(consumerCountChanged(int)),

this, SLOT(onConsumerValueChanged(int)));

connect(mProducer, SIGNAL(producerCountChanged(int)),

this, SLOT(onProducerValueChanged(int)));

}

ConProdDialog::~ConProdDialog()

{

delete ui;

}

void ConProdDialog::onBufferValueChanged(int bCount)

{

ui->bufferProgressBar->setValue(bCount);

}

void ConProdDialog::onProducerValueChanged(int pCount)

{

ui->producerProgressBar->setValue(pCount);

}

void ConProdDialog::onConsumerValueChanged(int cCount)

{

ui->consumerProgressBar->setValue(cCount);

}

// start button clicked

void ConProdDialog::on_startButton_clicked()

{

// disable the start button

ui->startButton->setEnabled(false);

// threads starat

mProducer->start();

mConsumer->start();

}

Пользовательский интерфейс выглядит так:

Покажем листинг остальных файлов:

main.cpp

#include "conproddialog.h"

#include <QApplication>

#include "conproddialog.h"

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

ConProdDialog w;

w.setWindowTitle("Semaphore: Consumer & Producer");

w.show();

return a.exec();

}

common.h

#ifndef COMMON_H

#define COMMON_H

#include <QSemaphore>

#include "myConstants.h"

extern char buffer[BufferSize];

extern QSemaphore freeBytes;

extern QSemaphore usedBytes;

#endif // COMMON_H

myConstants.h:

#ifndef MYCONSTANTS_H

#define MYCONSTANTS_H

const int DataSize = 100000;

const int BufferSize = 8192;

#endif // MYCONSTANTS_H

conproddialog.h:

#ifndef CONPRODDIALOG_H

#define CONPRODDIALOG_H

#include <QDialog>

#include "consumer.h"

#include "producer.h"

#include <QSemaphore>

namespace Ui {

class ConProdDialog;

}

class ConProdDialog : public QDialog

{

Q_OBJECT

public:

explicit ConProdDialog(QWidget *parent = 0);

~ConProdDialog();

public slots:

void onBufferValueChanged(int);

void onProducerValueChanged(int);

void onConsumerValueChanged(int);

private slots:

void on_startButton_clicked();

private:

Ui::ConProdDialog *ui;

Producer *mProducer;

Consumer *mConsumer;

};

#endif // CONPRODDIALOG_H

producer.h:

#ifndef PRODUCER_H

#define PRODUCER_H

#include <QThread>

#include <QTime>

class Producer : public QThread

{

Q_OBJECT

public:

explicit Producer(QObject *parent = 0);

void run();

signals:

void bufferFillCountChanged(int bCount);

void producerCountChanged(int count);

public slots:

};

#endif // PRODUCER_H

consumer.h:

#ifndef CONSUMER_H

#define CONSUMER_H

#include <QThread>

#include <QTime>

class Consumer : public QThread

{

Q_OBJECT

public:

explicit Consumer(QObject *parent = 0);

void run();

signals:

//void stringConsumed(const QString &text);

void bufferFillCountChanged(int cCount);

void consumerCountChanged(int count);

public slots:

};

#endif // CONSUMER_H

и наконец, .pro

ConProd2.pro:

#-------------------------------------------------

#

# Project created by QtCreator 2013-09-27T15:43:43

#

#-------------------------------------------------

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = ConProd2

TEMPLATE = app

SOURCES += main.cpp\

conproddialog.cpp \

consumer.cpp \

producer.cpp

HEADERS += conproddialog.h \

consumer.h \

producer.h \

common.h \

myConstants.h

FORMS += conproddialog.ui