Эксперт
Сергей
Сергей
Задать вопрос
Мы готовы помочь Вам.

Цель работы

Знакомство с многопоточным программированием и методами синхронизации потоков средствами Windows API.

Задание

  1. С помощью таблицы вариантов заданий выбрать граф запуска потоков в соответствии с номером варианта. Вершины графа являются точками запуска/завершения потоков, дугами обозначены сами потоки. Длину дуги следует интерпретировать как ориентировочное время выполнения потока. В процессе своей работы каждый поток должен в цикле выполнять два действия:
    1. выводить букву имени потока в консоль;
    2. вызывать функцию computation() для выполнения вычислений, требующих задействования ЦП на длительное время. Эта функция уже написана и подключается из заголовочного файла lab3.h, изменять ее не следует.
  2. В соответствии с вариантом выделить на графе две группы с выполняющимися параллельно потоками. В первой группе потоки не синхронизированы, параллельное выполнение входящих в группу потоков происходит за счет планировщика задач. Вторая группа синхронизирована семафорами и потоки внутри группы выполняются в строго зафиксированном порядке: входящий в групу поток передает управление другому потоку после каждой итерации цикла . Таким образом потоки во второй группе выполняются в строгой очередности.
  3. С использованием средств Windows API реализовать программу для последовательно-параллельного выполнения потоков в ОС Windows. Запрещается использовать какие-либо библиотеки и модули, решающие задачу кроссплатформенной разработки многопоточных приложений (std::thread, Qt Thread, Boost Thread и т.п.). Для этого необходимо написать код в файле lab3.cpp:
    1. Функция unsigned int lab3_thread_graph_id() должна возвращать номер графа запуска потоков, полученный из таблицы вариантов заданий.
    2. Функция const char* lab3_unsynchronized_threads() должна возвращать строку, состоящую из букв потоков, выполняющихся параллельно без синхронизации.
    3. Функция const char* lab3_sequential_threads() должна возвращать строку, состоящую из букв потоков, выполняющихся параллельно в строгой очередности друг за другом.
    4. Функция int lab3_init() заменяет собой функцию main(). В ней необходимо реализовать запуск потоков, инициализацию вспомогательных переменных (мьютексов, семафоров и т.п.). Перед выходом из функции lab3_init() необходимо убедиться, что все запущенные потоки завершились. Возвращаемое значение: 0 – работа функции завершилась успешно, любое другое числовое значение – при выполнении функции произошла критическая ошибка.
    5. Добавить любые другие необходимые для работы программы функции, переменные и подключаемые файлы.
    6. Создавать функцию main() не нужно. В проекте уже имеется готовая функция main(), изменять ее нельзя. Она выполняет единственное действие: вызывает функцию lab3_init().
    7. Не следует изменять какие-либо файлы, кроме lab3.cpp. Также не следует создавать новые файлы и писать в них код, поскольку код из этих файлов не будет использоваться во время тестирования.

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

В процессе своей работы каждый поток выводит свою букву в консоль. Оценка правильности выполнения лабораторной работы осуществляется следующим образом. Если потоки a и b согласно графу должны выполняться одновременно (параллельно), то в консоли должна присутствовать последовательность вида abababab (или схожая, например, aabbba); если потоки выполняются последовательно, то в консоли присутствует последовательность вида aaaaabbbbbb, причем после появления первой буквы b, буква a больше не должна появиться в консоли.

Количество букв, выводимых каждым потоком в консоль, должно быть пропорционально числу интервалов (длине дуги), соответствующей данному потоку на графе. При этом количество символов, выводимых в консоль каждым из потоков, должно быть не меньше чем 3Q и не больше чем 5Q, где Q – количество интервалов на графе, в течении которых выполняется поток. Множитель перед величиной Q следует выбрать одинаковым для всех потоков, задав его равным 3, 4 или 5.

Пример работы с графом потока

Рассмотрим граф запуска потоков, приведенный на рисунке ниже.

Программа, реализующая указанную на графе последовательность запуска потоков, должна запустить 5 потоков: abcd и e. Работу программы можно разбить на три временных интервала:

  1. С момента времени T0 до T1 работает только поток a.
  2. С T1 до T2 параллельно работают потоки bc и d.
  3. С T2 до T3 параллельно работают потоки d и e.

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

 

Сборка и тестирование

Для сборки кода рекомендуется создать проект в любой IDE, например, Visual Studio, CLion, Code::Blocks или аналогичной. Работоспособность тестов гарантируется при использовании компилятора VC11 (входит в Visual Studio 2012) или более позднего и компилятора GCC в составе пакета MinGW 5.0 или более позднего.

Рекомендуется локально запускать тесты несколько раз даже в случае их успешного выполнения, поскольку последовательность выполнения потоков может отличаться от запуска к запуску программы и ошибка в решении задачи синхронизации потоков может проявляться не всегда. Если тесты пройдены успешно, можно выполнить команды git add lab3.cpp, git commit и git push, после чего убедиться, что тесты также успешно пройдены и в репозитории.

Содержание отчета

  • Титульный лист
  • Цель работы
  • Задание на лабораторную работу
  • Граф запуска потоков
  • Результат выполнения работы
  • Исходный код программы с комментариями
  • Выводы

 

Была ли полезна данная статья?
Да
67.47%
Нет
32.53%
Проголосовало: 83

или напишите нам прямо сейчас:

Написать в WhatsApp Написать в Telegram