Лабораторная Работа – Разработка многопоточного приложения средствами POSIX в ОС Linux или Mac OS
Цель работы
Может быть интересно
Знакомство с многопоточным программированием и методами синхронизации потоков средствами POSIX.
Задание
- С помощью таблицы вариантов заданий выбрать граф запуска потоков в соответствии с номером варианта. Вершины графа являются точками запуска/завершения потоков, дугами обозначены сами потоки. Длину дуги следует интерпретировать как ориентировочное время выполнения потока. В процессе своей работы каждый поток должен в цикле выполнять два действия:
- выводить букву имени потока в консоль;
- вызывать функцию computation() для выполнения вычислений, требующих задействования ЦП на длительное время. Эта функция уже написана и подключается из заголовочного файла lab2.h, изменять ее не следует.
- В соответствии с вариантом выделить на графе две группы с выполняющимися параллельно потоками. В первой группе потоки не синхронизированы, параллельное выполнение входящих в группу потоков происходит за счет планировщика задач (см. примеры 1 и 2). Вторая группа синхронизирована семафорами и потоки внутри группы выполняются в строго зафиксированном порядке: входящий в групу поток передает управление другому потоку после каждой итерации цикла (см. пример 3 и задачу производителя и потребителя). Таким образом потоки во второй группе выполняются в строгой очередности.
- С использованием средств POSIX реализовать программу для последовательно-параллельного выполнения потоков в ОС Linux или Mac OS X. Запрещается использовать какие-либо библиотеки и модули, решающие задачу кроссплатформенной разработки многопоточных приложений (std::thread, Qt Thread, Boost Thread и т.п.). Для этого необходимо написать код в файле lab2.cpp:
- Функция unsigned int lab2_thread_graph_id() должна возвращать номер графа запуска потоков, полученный из таблицы вариантов заданий.
- Функция const char* lab2_unsynchronized_threads() должна возвращать строку, состоящую из букв потоков, выполняющихся параллельно без синхронизации (см. примеры в файлах lab2.cpp и lab2_ex.cpp).
- Функция const char* lab2_sequential_threads() должна возвращать строку, состоящую из букв потоков, выполняющихся параллельно в строгой очередности друг за другом (см. примеры в файлах lab2.cpp и lab2_ex.cpp).
- Функция int lab2_init() заменяет собой функцию main(). В ней необходимо реализовать запуск потоков, инициализацию вспомогательных переменных (мьютексов, семафоров и т.п.). Перед выходом из функции lab2_init() необходимо убедиться, что все запущенные потоки завершились. Возвращаемое значение: 0 – работа функции завершилась успешно, любое другое числовое значение – при выполнении функции произошла критическая ошибка.
- Добавить любые другие необходимые для работы программы функции, переменные и подключаемые файлы.
- Создавать функцию main() не нужно. В проекте уже имеется готовая функция main(), изменять ее нельзя. Она выполняет единственное действие: вызывает функцию lab2_init().
- Не следует изменять какие-либо файлы, кроме lab2.cpp. Также не следует создавать новые файлы и писать в них код, поскольку код из этих файлов не будет использоваться во время тестирования.
Последовательное выполнение потоков может обеспечиваться как за счет использования семафоров, так и с помощью функции pthread_join(). Запускать потоки можно все сразу в функции lab2_init(), а можно и по одному (или группами) из других потоков.
В процессе своей работы каждый поток выводит свою букву в консоль. Оценка правильности выполнения лабораторной работы осуществляется следующим образом. Если потоки a и b согласно графу должны выполняться одновременно (параллельно), то в консоли должна присутствовать последовательность вида abababab (или схожая, например, aabbba); если потоки выполняются последовательно, то в консоли присутствует последовательность вида aaaaabbbbbb, причем после появления первой буквы b, буква a больше не должна появиться в консоли.
Количество букв, выводимых каждым потоком в консоль, должно быть пропорционально числу интервалов (длине дуги), соответствующей данному потоку на графе. При этом количество символов, выводимых в консоль каждым из потоков, должно быть не меньше чем 3Q и не больше чем 5Q, где Q – количество интервалов на графе, в течении которых выполняется поток. Множитель перед величиной Q следует выбрать одинаковым для всех потоков, задав его равным 3, 4 или 5.
Пример работы с графом потока
Рассмотрим граф запуска потоков, приведенный на рисунке ниже.
Программа, реализующая указанную на графе последовательность запуска потоков, должна запустить 5 потоков: a, b, c, d и e. Работу программы можно разбить на три временных интервала:
- С момента времени T0 до T1 работает только поток a.
- С T1 до T2 параллельно работают потоки b, c и d.
- С T2 до T3 параллельно работают потоки d и e.
Пусть потоки b, c и d должны выполняться параллельно без использования средств синхронизации, а потоки d и e должны выполняться параллельно в строгой очередности друг за другом за счет использования семафоров. В этом случае возможны следующие варианты последовательностей символов на выходе программы:
В файле lab2_ex.cpp приведен пример выполнения лабораторной работы для рассмотренного графа. Скомпилировать и запустить данный пример можно с помощью последовательности команд
g++ lab2_ex.cpp main.cpp -lpthread -o lab2_ex
./lab2_ex
Сборка и тестирование
Скомпилировать программу из консоли без использования линковщика можно следующим образом. Сначала необходимо перейти в директорию, в которой находятся исходные файлы lab2.h, lab2.cpp и main.cpp. Далее все команды будут приводиться относительно этой директории.
Компиляция программы в файл a.out в текущей папке:
g++ lab2.cpp main.cpp -lpthread
При использовании старой версии компилятора GCC может потребоваться дополнительно указать ключ -std=c++11. В этом случае компилятор выведет соответствующее сообщение в консоль.
Запуск скомпилированной программы: ./a.out. При желании можно указать ключ -o при компиляции, в этом случае можно будет задать более осмысленное имя итогового файла с программой, нежели a.out. Например,
g++ lab2.cpp main.cpp -lpthread -o lab2
./lab2
Тестирование
Для запуска тестов на локальной машине предварительно потребуется собрать библиотеку gtest. Для этого, перед первой компиляцией тестов, необходимо выполнить следующую последовательность команд:
cd test/gtest
GTEST_DIR=$(pwd)
g++ -isystem “${GTEST_DIR}”/include -I”${GTEST_DIR}” -pthread -c “${GTEST_DIR}”/src/gtest-all.cc
ar -rv libgtest.a gtest-all.o
В консоли должен появиться текст
ar: creating libgtest.a
a – gtest-all.o
Также можно убедиться с помощью команды ls -l, что в текущей папке появился файл libgtest.a и его размер больше нуля байт. Если все прошло успешно, в дальнейшем вызывать эти команды более не потребуется.
Далее необходимо вернуться в директорию test, расположенную в корневой директории репозитория. Для компиляции тестов необходимо выполнить команду
g++ ../lab2.cpp tests.cpp -lpthread -lgtest -o runTests -I gtest/include -L gtest
При необходимости следует добавить ключ -std=c++11. Запустить тесты можно командой ./runTests. Если не все тесты завершились успешно, необходимо внести изменения в файл lab2.cpp, добившись правильного выполнения задания, затем повторно скомпилировать тесты командой g++ ../lab2.cpp tests.cpp -lpthread -lgtest -o runTests -I gtest/include -L gtest, после чего вновь запустить процесс тестирования.
Рекомендуется локально запускать тесты несколько раз даже в случае их успешного выполнения, поскольку последовательность выполнения потоков может отличаться от запуска к запуску программы и ошибка в решении задачи синхронизации потоков может проявляться не всегда. Если тесты пройдены успешно, можно выполнить команды git add lab2.cpp, git commit и git push, после чего убедиться, что тесты также успешно пройдены и в репозитории.
Примеры
Перед выполнением лабораторной работы рекомендуется ознакомиться с синхронизации потоков. Также возможный подход к выполнению лабораторной работы показан в файле . В данном примере потоки b, c и d не синхронизированы, а потоки d и e синхронизированы парой семафоров и выполняются в строгой последовательности (чередуются) по аналогии с задачей производителя-потребителя.
Тело потока может быть реализовано в виде функции, имеющей следующий вид:
pthread_mutex_t lock;
void* thread_a_(void *ptr)
{
for (int i = 0; i < 3; ++i) {
pthread_mutex_lock(&lock);
std::cout << “a” << std::flush;
pthread_mutex_unlock(&lock);
computation();
}
return ptr;
}
Здесь три раза выводится буква потока (a), что соответствует дуге графа длиной в один интервал. Команда std::flush используется для немедленного вывода буквы потока в консоль, чтобы избежать буферизации на уровне операционной системы. В качестве альтернативного решения можно полностью отключить буферизацию стандартного потока вывода с помощью функции, например, так: std::setbuf(stdout, NULL).
После вывода каждой буквы в консоль обязательно вызывается функция computation() для имитации проведения вычислений и выполнения ресурсо-затратных операций. В большинстве случаев вызов этой функции приводит к переключению контекста и началу выполнения другого потока. Это происходит прежде, чем данным потоком в консоль будет выведена следующая буква.
В зависимости от реализации операций ввода-вывода в операционной системе, а также от версий стандартной библиотеки и компилятора языка C/C++, простой вызов std::cout << “a” может быть как атомарной операцией, так и не атомарной. В любом случае, команда std::cout << “a” << std::flush не является атомарной, поскольку каждый оператор << гарантировано является отдельной операцией. Поэтому, чтобы избежать проблем с выводом в консоль, при работе с общим ресурсом (стандартным потоком вывода) используется мьютекс. Подробнее см. соответствующие.
Содержание отчета
- Титульный лист
- Цель работы
- Задание на лабораторную работу
- Граф запуска потоков
- Результат выполнения работы
- Исходный код программы с комментариями
- Выводы
Здравствуйте. Скажите пожалуйста, планирую поступать в магистратуру на факультет Психологии « Психология личности»в РГГУ скажите пожалуйста, есть ли у вас, ответы на вступительные экзамены? так как, планирую, сделать акцент на бюджет. Спасибо.
Арсений, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Дистанционная помощь в защите ВКР
Анастасия, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Здравствуйте. Нужна срочно практическая часть вкр, третья глава. Скину похожие работы, на которые можно ориентироваться
Александр, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
вкр по теме: экологический туризм России : анализ состояния, проблемы и перспективы
Людмила, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Здравствуйте вы защищаете ВКР?
Ольга, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Написать магистерскую ВКР на тему «Совершенствование логистических бизнес-процессов на примере торговой компании». Не менее 100 страниц.
Миша, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Здравствуйте нужна работа Вкр
Лена, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.
Написать ВКР 3 раздела Тема строительство строительство жилого дома с применением каркасно-монолитных технологий Антиплагиат от 75% ПЗ и чертежи
Владимир, здравствуйте! Прошу Вас прислать всю необходимую информацию на почту info@otlichnici.ru и написать что необходимо выполнить. Я посмотрю описание к заданиям и подскажу вам по стоимости и срокам выполнения.