" title="Написать письмо">Написать письмо
Донаты на карту ВТБ:
5368 2902 0040 0838

Статистика

Пользователи : 1
Статьи : 2077
Просмотры материалов : 7620687
 
Многопоточность: получилось-2 (02.08.2024). Печать E-mail
2024 - Август
02.08.2024 12:50
Save & Share
Предыдущая удача с многопоточностью в Qt v.5.15.2 (а также наличие быстрого сервера PostgreSQL) - казалось бы, поставила жирную точку: писать свой личный софт придётся в Qt. Но если бы всё было хорошо - то этой статьи бы не было.



Проблемы:
- Qt - глючное говно (вдобавок ещё покинувшее РФ из-за СВО) с убогой концепцией сигналов-слотов, расположения графических элементов в ui единой мешаниной (без вложенности в GroupBox) и т.д.;
- Qt в состав новой Astra Linux не входит - нужно вручную ставить из репозитория разработчика, в своё время угрохав кучу времени на список необходимых пакетов;
- в Qt новой версии что-то нахимичили с созданием графиков - и компонентов QChart/Chart/QCustomPlot в ней больше нет (ни проинклудить, ни в проект не приписать). Все старые советы на форумах становятся бесполезными, а по новой версии информации ещё нет;
- скопировать старый компонент из стороннего старого проекта не получится, т.к. последнего больше нет;
- предполагалось, что виджет graphicsView заменит графики - но по скудной информации он видится как отображатель рисунков, создаваемых с помощью XIMAGEDESC/QImage/QPainter и т.д.

Соответственно, думал мигрировать личный проект с Borland C++ Builder v.6.0 (накодил многопоточность всего на 2 ядра, по прошлым экспериментам, - и то еле-еле) на Qt v.5.15.2 (многопоточность на все ядра). Но опять вырвало после пары попыток (как с недавним желанием переписать другой личный проект с Visual Basic v.6.0 на Qt). Было решено учиться делать многопоточность на BCB6: чтобы, заодно, исходники не переписывать.

Проблемы - те же самые: примеры из интернета не работают (разбавление правды ложью - один из методов пропаганды, поэтому как назвать авторов этих примеров - х.з.). И тут, внезапно, среди всего этого интернет-говна, находится золото. Один-единственный человек, на каком-то богом забытом сайте, с хрен-пойми-каким названием, в жопе мира поисковика, пишет: "File→New→Other...→прокрутить→Thread Object". Всё это время объект потоков существовал надёжно спрятанным - и никто о нём не написал.

Дальше уже было делом техники:
- каждый поток изначально получается в отдельных CPP-H-файлах. После отработки можно объединить их в 1 общий;
- не надо никаких классов с собственной писаниной изобретать: просто берёшь то, что написано в автоматически созданных файлах;
- в начале метода Execute() нужно написать "FreeOnTerminate = true;": для освобождения памяти от потока, каким бы способом (Suspend/Terminate/закончился) он ни был остановлен;
- как в случае Qt, глобально объявленный объект потока не хочет отрабатывать по второму разу. Поэтому пока - создаётся локально. Отсюда баг: при нажатии на одну и ту же кнопку несколько раз - создаются свои объекты потоков, выполняющиеся одновременно. Решение простое: глобальная переменная на каждый поток, анализ её в теле потока - если переменная true, значит оригинал потока уже существует, значит завершить копию потока без выполнения;
- пока неясно, как заблокировать поток. Значит, если по итогу не выйдет, - просто составлять код таким образом, чтобы потоки друг другу не мешали;
- успешная загрузка всех ядер виртуальных процессоров на виртуальной машине на 100%.

(добавлено 03.08.2024) Разное:
- создание потока в одну строку (false - автоматический запуск, true - вручную с помощью Resume()): "TThread *Thread = new TThread(true);";
- в Borland используются понятия "синхронизация потока с VCL" и "блокирование элементов". Например, "Synchronize(my_public_function_in_class_thread___to_work_with_interface)" - обеспечивает безопасное взаимодействие функции потока с библиотекой VCL (считай, со всеми элементами интерфейса - и не только с ними). В свою очередь, элементы интерфейса нужно блокировать методом lock(), а также проверять в другом потоке вида "пока объект заблокирован - тупо ждать". Synchronize нужно осторожно вызывать в циклах, т.к. у неё длительное время выполнения из-за вызова самой функции в её параметре;
- доступно показана работа с критическими секциями как методом блокировки потоков относительно друг друга. Пишется в классе потока в private, инкдулится Windows.h. Пишется в Execute потока: InitializeCriticalSection(&csSection), EnterCriticalSection(&csSection), выполняемый код, LeaveCriticalSection(&csSection), DeleteCriticalSection(&csSection);
- можно присвоить потоку системное имя при его создании - и потом, например, получить список потоков из самой ОС и бахнуть конкретный у конкретного приложения.

В Qt же используется понятие "блокировка/синхронизация" именно потоков друг с другом - никакой блокировки элементов интерфейса нет. Проанализировав чужие исходники на работе от Qt v.5.3, пришёл к выводу:
- можно многопоточность реализовать с такими извратами - что даже пол-литра водки не помогает (при этом всё работает);
- часть потоков в программном комплексе лочатся, часть нет. С учётом функционирования программы ~10 лет и отсутствия ошибок с потоками - блокировка потока не является обязательной;
- непонятен механизм блокировки: класс потока просто имеет в себе "QMutex *mutex_ptr;", блокируемый путём "QMutexLocker locker(&class_thread->mutex);". И больше с этим locker и mutex_ptr ничего не делается, в т.ч. нет и разблокировки потока. И в сам *mutex_ptr ничего не помещается: нечто хаотично созданное (ранее при инициализации потока) блокируется - и всё. А заблокировалось или нет - по факту х.з. И пишут ещё, что мутексы медленнее критических секций - вообще зачем такой изврат прошлого нужен;
- манипуляции в билдере с потоками, что описаны выше: уже проверены и работают - полное понимание работы с потоками, остаётся переписать неправильную прошлую реализацию в своём ПО. Тогда только ядру №1 функция отдавалась при помощи "SetThreadAffinityMask(GetCurrentThread(), 1 << 1)": иначе не работало вообще. В Qt же часть информации остаётся не совсем понятной, а также труднопроверяемой. Вот ещё один показатель, что в Qt лезть не надо: тонну времени потеряешь на изучении всех этих нестыковок. Ещё показателем является качество кода среды программирования: в билдере - ни одного Warning; в Qt же их всегда столько - что мало кто обращает на них внимание (и внутри собственных инклудов могут быть спокойно). Соответственно, можно пропустить что-то важное.

Вот и попался в ловушку процессорных гигагерц. Intel E5-2696 V2: 12 ядер по 2.5ГГц, 24 потока - 1.25ГГц/поток. Виртуальная машина, используя 1 "процессор", - на самом деле использует 1 поток. Если ранее с AMD A10-5700 было 4 ядра по 3.7ГГц и 4 потока - такая виртуальная машина запускалась на 3.7ГГц. То есть, купив серверный процессор, лучший по энергоэффективности и суммарному количеству ГГц, - без многопоточности скорость работы некоторых приложений упала до 2.96 раза. Хорошо, что за границей в многопоточность умеют, - и, суммарно, прирост в скорости работы большинства приложений просто гигантский. Но вот с самописными, российскими (кроме 7-Zip) и старыми приложениями - залёт. Поэтому пришлось изучать многопоточность аж у 2 языков программирования - и, суммарно с 2.5 попытки, получился успех.

Однако многопоточность запускаемых функций при частоте 1.25ГГц не всегда может спасти. Например, сортировка огромного количества информации на Intel i5-10400 с ядром 4.3ГГц (разогнан) заняла 15с, а на E5-2696 V2 в виртуальной машине (1 поток всего лишь - но почему-то всё ядро занял) - 26с (при условии, что нужно уложиться в минуту). То есть, скоро (размер данных стремительно растёт) уже внутри функции нужно будет организовывать многопоточность (от виртуальной машины не отказаться). То есть, одну половину огромного массива данных посылать в 1 поток, другую половину во второй - а потом результаты сортировки соединять и сортировать дальше уже в третьем.

(добавлено 04.08.2024) В отличие от Qt, многократное выполнение потока в Borland не приводит к утечкам памяти (проверено на ~240 запусках в течение 2ч) - FreeOnTerminate работает прекрасно, выполняя удаление динамически созданного пользователем объекта потока - без его участия.
Обновлено ( 05.08.2024 18:16 )
 
 

Последние новости


©2008-2024. All Rights Reserved. Разработчик - " title="Сергей Белов">Сергей Белов. Материалы сайта предоставляются по принципу "как есть". Автор не несет никакой ответственности и не гарантирует отсутствие неправильных сведений и ошибок. Вся ответственность за использование материалов лежит полностью на читателях. Размещение материалов данного сайта на иных сайтах запрещено без указания активной ссылки на данный сайт-первоисточник (ГК РФ: ст.1259 п.1 + ст.1274 п.1-3).

Много статей не имеет срока устаревания. Есть смысл смотреть и 2011, и даже 2008 год. Политика сайта: написать статью, а потом обновлять ее много лет.
Рекламодателям! Перестаньте спамить мне на почту с предложениями о размещении рекламы на этом сайте. Я никогда спамером/рекламщиком не был и не буду!
Top.Mail.Ru