223 / 191 / 34
Регистрация: 19.02.2021
Сообщений: 1,387
|
|||||||||||
1 | |||||||||||
Уперся в тупик с потоками. Прошу подсказки30.09.2023, 14:04. Показов 1291. Ответов 50
Метки нет Все метки)
(
Здравствуйте!
Есть у меня небольшая самописная демка, писанная когда-то на Delphi. Решил ее переписать на C++ в рамках самообразования. Демка простая - одни объекты гоняются за другими, я на ней тренировался выполнять параллельные расчеты. На Delphi все работало "на ура", а вот с C++ возникли проблемы. Архитектура примерно такая: 1. Есть Контроллер, который отвечает за перемещение и взаимодействие объектов. Он крутится в отдельном потоке. Вернее, не он целиком, а только один из его методов. Возможно, в этом и проблема. Метод запускается через std::thread(&CController::Execute,m_pController).detach(). detach() потому то при join() все зависало. 2. Есть "Визуализатор", который отвечает за отображение объектов. Его процедуры, отвечающие за отрисовку, вызываются из Контроллера. "Визуализатор" является членом класса Контроллера по специальному интерфейсу. 3. Есть что-то типа пула вспомогательных потоков, (принадлежат классу Контроллера), который занимаются непосредственно расчетами. В "Визуализаторе" предусмотрен диалог с настройками, по выходу из которого старый Контроллер уничтожается и создается новый экземпляр с новыми настройками. И вот у меня не получается корректно уничтожить экземпляр Контроллера((((( В методе, который запускается в потоке, есть булевский флаг, который контролирует цикл
Манипуляции с executeMutex - это попытки как-то разобраться/понять, почему изменение флага m_bTerminate не приводит к завершению цикла (не вызывается m_pView->OnControllerTerminate() Сам проект писан на C++ +wxWidgets. Могу выложить, если нужно.
0
|
|
30.09.2023, 14:04 | |
Ответы с готовыми решениями:
50
Прошу подсказки Прошу подсказки прошу подсказки Прошу подсказки |
фрилансер
5221 / 4757 / 1000
Регистрация: 11.10.2019
Сообщений: 12,475
|
|
30.09.2023, 14:22 | 2 |
это - попытка (удачная) сделать дедлок
![]() m_bTerminate - какой тип этой переменной ? Надеюсь, это std::atomic<bool> Добавлено через 1 минуту а тут этот дедлок и совершается. Поэтому и join залипает А вообще, эта строка ничего не делает (кроме дедлока, хм)
0
|
223 / 191 / 34
Регистрация: 19.02.2021
Сообщений: 1,387
|
|
30.09.2023, 15:18 [ТС] | 3 |
Это акт отчаянья!
![]() И это не для join(), это для detach(). После того, как у меня зависал join() (без этих дурацких executeMutex.lock(); executeMutex.unlock()), я решил поэкспериментировать с detach(). Я думал вот как: 1. Перед рабочим циклом потока сделать executeMutex.lock(). 2. Вызвав Terminate(), установить флаг и выполнить executeMutex.lock() (в другом методе, который в основном потоке. Может, в этом дело). Здесь (по моему ожиданию) все останавлиается. 3. Далее, Execute() отработав внутри цикла все процедуры, выходит по m_bTerminate и перед выходом из процедуры разблокирует мьютекс. 4. Что позволит продолжить код, стоящий на паузе в п.2. 5. А потом уже я могу нормально удалить Контроллер. Добавлено через 1 минуту Да. Не помогло. Я его пытался делать и глобальным, и членом класса. Походу, я что-то где-то упустил в теории. Не могу понять, почему рабочий цикл не завершается по m_bTerminate...
0
|
фрилансер
5221 / 4757 / 1000
Регистрация: 11.10.2019
Сообщений: 12,475
|
|
30.09.2023, 15:31 | 4 |
мутекс должен локаться на очень краткое время - в критической секции, где нужен синхронизированных доступ к данным, использующимся в разных потоках. То есть, сейчас он у тебя используется как-то неправильно
Вообще, не видя проект, трудно что-то подсказать, поэтому прицепи какой-то пример кода, демонстрирующий проблему (если проект большой) в самом проекте лично я копаться не буду, там, судя по всему, проще всё заново переписать ![]() А кто-нибудь другой, вдруг, захочет покопаться
0
|
223 / 191 / 34
Регистрация: 19.02.2021
Сообщений: 1,387
|
|||||||||||||||||||||||||||||||
30.09.2023, 16:43 [ТС] | 5 | ||||||||||||||||||||||||||||||
Там много чего нужно цеплять.)))
1. Контроллер является членом класса Визуализатора. 2. Визуализатор вызвает метод Контроллера, где устанавливается флаг. Вызывает в своем (основном) потоке. 3. А в этот момент Контроллер в дополнительном потоке может пинать Визуализатор для отрисовки объектов. Тут такое... На Delphi оно работает, как часики, но там собственный враппер над std::thread, возможно, там все гораздо грамотнее организовано, чем я наваял "с нуля"))) Может ли дело быть в том, что из метода, который запускается в основном потоке, устанавливается флаг для метода, который запускается в дополнительном потоке? Добавлено через 41 минуту Что показал эксперимент: 1. Отключил все дополнительные потоки, оставил только тот, где работает Контроллер. 2. Вывел m_bTerminate в статистику, которую постоянно отображает Визуализатор. Вот ключевой код: Хедер:
void WaspFlyGLFrm::OnControllerTerminate()
Дальше все тупо висит на строке m_pControllerThread->join() при этом Контроллер продолжает работать (это видно по отображаемой Визуализатором статистике), в которой видно, что m_bTerminate не изменился, так и остался false. Как такое может быть? С одной стороны - флаг изменился, т.к., из цикла мы вышли и попали в OnControllerTerminate() С другой сторны - Контроллер продолжает работать. И показывает, что его флаг все еще false. У меня праноидальное подозрение, что Контроллер каким-то образом то ли работает в нескольких потоках, то ли я вообще ничего не понимаю... Добавлено через 8 минут Здесь ошибка, должно быть
Висим на join(), поток продолжает работать, показывает, что флаг = false, хотя мы находимся в том месте, куда можно попасть только если флаг = true и процедура потока завершена. ![]()
0
|
223 / 191 / 34
Регистрация: 19.02.2021
Сообщений: 1,387
|
|
30.09.2023, 17:31 [ТС] | 6 |
Вот объясните мне это:
Объявил m_bTerminate, как static: Из Визуализатора директивно присвоил ему true: Потом захожу в Terminate(), где должен установится этот же флаг в true и вижу там: Это как??? Это одна переменная. Одна-единственная, глобальная, 100% проверил. Чего я не знаю?
0
|
223 / 191 / 34
Регистрация: 19.02.2021
Сообщений: 1,387
|
||||||
30.09.2023, 17:36 [ТС] | 7 | |||||
В случае
В DestroyController() флаг получает значение true и тут же в Terminate() он уже false При создании потока создается полная копия всех переменных, в том числе и статических? Или что это такое?
0
|
671 / 474 / 215
Регистрация: 06.09.2013
Сообщений: 1,301
|
|
30.09.2023, 17:38 | 8 |
Constcat, в
OnControllerTerminate поток пытается вызвать join самого себя - это дедлок. Эта функция должна вызываться из другого потока (например, который запустил Execute).
0
|
223 / 191 / 34
Регистрация: 19.02.2021
Сообщений: 1,387
|
|
30.09.2023, 17:45 [ТС] | 9 |
Это эксперимент был, я просто пробовал различные варианты.
План был такой: 1. В одной процедуре, которая крутится в фоновом потоке, захватывается мьютекс. Потом начинается какая-то длительная работа. 2. В другой процедуре из основного потока нужно подождать окончание этой работы (про сигналы и события я знаю, повторю - это эксперимент))) 3. Для этого в другой процедуре я пытаюсь захватить этот же мьютекс, процедура останавливается в этом месте и ждет. 4. Когда в первой процедуре работа закончена, там освобождается мьютекс. 5. После этого другая процедура захватывает этот мютекс, как признак, что первая процедура закончила работу.
0
|
фрилансер
5221 / 4757 / 1000
Регистрация: 11.10.2019
Сообщений: 12,475
|
||||||
30.09.2023, 17:59 | 10 | |||||
тут не нужна динамика
мутекс придумали не для этого. А для написанного выше достаточно флаг
0
|
671 / 474 / 215
Регистрация: 06.09.2013
Сообщений: 1,301
|
||||||
30.09.2023, 18:00 | 11 | |||||
Мьютекс тут вообще не при чем, я про это:
0
|
фрилансер
5221 / 4757 / 1000
Регистрация: 11.10.2019
Сообщений: 12,475
|
||||||
30.09.2023, 18:13 | 12 | |||||
![]() Решение
Constcat, https://onlinegdb.com/XAPZqYDcb
1
|
223 / 191 / 34
Регистрация: 19.02.2021
Сообщений: 1,387
|
||||||
30.09.2023, 22:26 [ТС] | 13 | |||||
Алексей1153, Спасибо, возьму за образец, попробую.)))))
По результату отпишусь. Получается, нужно не снаружи метод Контроллера запускать в потоке, а изнутри Контроллера... Вот за эту подсказку - огромное спасибо! Добавлено через 25 минут Если не сложно, объясните, плз, эту конструкцию:
0
|
2682 / 2151 / 674
Регистрация: 29.06.2020
Сообщений: 7,960
|
|
30.09.2023, 22:37 | 14 |
именованный захват по ссылке
Добавлено через 4 минуты Хотя более точно : захват по ссылке с инициализацией.
0
|
фрилансер
5221 / 4757 / 1000
Регистрация: 11.10.2019
Сообщений: 12,475
|
||||||
30.09.2023, 22:51 | 15 | |||||
захват по ссылке с переименованием
(хотя, я дал полю лямбды такое же имя, как захваченная переменная) но можно действительно сменить имя для ссылки, например
0
|
223 / 191 / 34
Регистрация: 19.02.2021
Сообщений: 1,387
|
|
30.09.2023, 23:20 [ТС] | 16 |
Ага, понял. Еще почитал про это в инете.
Но пришлось от лямбды отказаться. У меня там обращение к членам и методам класса, попытка передать в лямбду this почему-то не получилась (хотя я уже примерно понимаю, почему, там был логический косяк)))) Я завел еще один метод (в котором рабочий цикл) и его уже запускаю в потоке из Execute()) Все заработало! Во всяком случае, больше не виснет и не падает с SIGSEGV. Сейчас переделаю пул вычислительных дополнительных потоков по вашему образцу, посмотрю, как оно будет работать.))) В любом случае - огромное спасибо!
0
|
фрилансер
5221 / 4757 / 1000
Регистрация: 11.10.2019
Сообщений: 12,475
|
|
30.09.2023, 23:31 | 17 |
0
|
0 / 0 / 0
Регистрация: 01.10.2023
Сообщений: 3
|
|
01.10.2023, 01:09 | 18 |
Не по теме: подскажите, почему именно такой захват, а не просто [this] например? Искал инфу, нашел что в с++11 перемещение в лямбду делали [var=std::move(var)] а в с++14 вот так.
0
|
фрилансер
5221 / 4757 / 1000
Регистрация: 11.10.2019
Сообщений: 12,475
|
|
01.10.2023, 06:40 | 19 |
4blK4blPblK, так я не использую this, использую всего одно поле класса.
Перемещать мне там не нужно, мне нужна именно ссылка
0
|
0 / 0 / 0
Регистрация: 01.10.2023
Сообщений: 3
|
|
01.10.2023, 11:52 | 20 |
а, то есть тут можно было и весь this захватить, но одно поле - экономнее? понял, спс.
0
|
01.10.2023, 11:52 | |
01.10.2023, 11:52 | |
Помогаю со студенческими работами здесь
20
Прошу подсказки и консультации Прошу подсказки новичку Прошу подсказки по MVC и соединению с БД Прошу подсказки - определиться с идеологией Прошу подсказки - куда копать? Прошу подсказки в настройке XenForo Не срабатывает clearInterval. Прошу подсказки Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |