Описанное ниже предлагается выполнить на C++ без использования сторонних библиотек, оформив в виде компилирующегося и запускающегося проекта для QMake/CMake на выбор. Использование Qt в основной части задания допускается, но не рекомендуется ограничиваться встроенными классами (очевидно, что тестовое окошко делать лучше именно на Qt, но свести всю многопоточность к вызову QtConcurrent::run
было бы неправильно, что станет ясно из последующих уточнений). Проект должен быть совместим с MSVC 2015+/GCC 5.4.x+/Qt 5.6+
Предлагается реализовать пул потоков, класс для одновременного многопоточного выполнения произвольных задач, а также небольшое оконное приложение для проверки работоспособности получившегося решения.
Назовём классThreadPool
, он должен уметь следующее:
- Обладать методом для добавления задачи. Задачей считаются любые свободные функции и лямбда-выражения (ну, точнее, замыкания). Поддерживать методы произвольных классов в этом качестве не обязательно, на усмотрение реализующего.
- Уметь быть запущенным и остановленным после запуска в произвольный момент времени. Запуск стартует потоки, которые (очевидно) начинают выполнять задачи. Остановка удаляет те задачи, выполнение которых ещё не началось, а также тормозит те, которые выполняются на момент остановки.
- Уметь управлять количеством потоков, которое задаётся до запуска пула. Предположим для простоты, что это число от 1 до 30. Задач может быть больше, чем рабочих потоков, те задачи, что ещё не обрабатываются, добавляются в очередь. Порядок получения задач рабочими потоками тот же, в котором задачи были добавлены.
- Рабочие потоки после запуска циклично получают задачу из списка добавленных, после этого выполняют её, после этого берут следующую. Если задачи закончились -- спят, либо завершаются, на усмотрение реализующего. Главное то, что если количество добавленных к выполнению задач превышает максимальное количество потоков, все потоки должны делать что-то полезное.
- Иметь возможность удалить ("отменить") конкретную задачу до того, как она начала выполняться. Удалить выполняющуюся задачу нельзя (для простоты).
- (Необязательный бонус) В случае, если задача предполагает получение результата, должен присутствовать способ (сюрприз!) этот результат получить
Дабы продемонстрировать, что пул потоков работает, предлагается реализовать окошко со следующими возможностями:
- Пусть будет 3 типа задач, выполнение которых достаточно длительно, чтобы это заметить, а реализация не слишком трудоёмка. Предлагается выбрать копирование файла из одного места в другое (файлы могут быть 300 - 1000Мб); вычисление N-ого числа Фибоначчи; сортировка достаточно большого массива целых чисел (дополнительный лайк за какую-нибудь кривую сортировку, например, пузырьком, чтобы это занимало существенно больше секунды), предварительно сгенерированного случайным образом.
- Должны быть кнопки "старт", "стоп", которые запускают и останавливают поток
- Должен быть способ задавать количество рабочих потоков
- Должны быть способы ввести пути для файлов (исходный и назначения); номер числа Фибоначчи для вычисления; размер случайного массива и диапазон чисел в нём
- Должна быть кнопка "добавить" и список/таблица/что-угодно-вообще для отображения статуса задач. Следует предусмотреть какой-то очевидный способ удалять любые стоящие в очереди задачи на своё усмотрение.
- Для каждой задачи должны быть статусы "В очереди"/"Выполняется"/"Завершена", отражающие реальное состояние каждой задачи
- Было бы неплохо, если бы где-то отражалось, что пул выполнил все задачи
Всё просто, код пула потоков должен быть неплох, а окошко ни в коем случае не должно ломаться. Сомнения на тему деталей реализации следует трактовать в свою пользу == в пользу минимальных усилий по реализации (надёжность важнее, чем изощрённость). Основное и очевидное:
- Valgrind не должен находить утечек памяти
- Никакое, даже самое внезапное, неожиданное и бессмысленное взаимодействие с окошком не должно приводить к его краху. Можно упростить для себя интерфейс с этой целью, но им всё равно должно быть возможно воспользоваться по назначению (пункт ниже).
- Хочется, чтобы можно было выбрать количество потоков, создать мышкой 40-50-60 заданий, нажать "старт" и смотреть как что-то происходит. Потом нажать "стоп".
- Стоит понимать, что задачи для выполнения потоками выбраны произвольны, не стоит привязывать реализацию пула потоков к их смыслу, на их месте могло быть что угодно.
- Оформление (внешний вид) интерфейса принципиально никак не важно, но окошко с хаотично накиданными компонентами будет говорить о том, что автор не в состоянии нормально сделать даже такой простой концепт.
- Ну и, конечно же, потоки в пуле должны корректно работать
На любые уточняющие вопросы можно получить ответ. GL;HF