Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.50/8: Рейтинг темы: голосов - 8, средняя оценка - 4.50
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431

Уперся в тупик с потоками. Прошу подсказки

30.09.2023, 14:04. Показов 2408. Ответов 50
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!
Есть у меня небольшая самописная демка, писанная когда-то на Delphi. Решил ее переписать на C++ в рамках самообразования.
Демка простая - одни объекты гоняются за другими, я на ней тренировался выполнять параллельные расчеты. На Delphi все работало "на ура", а вот с C++ возникли проблемы.

Архитектура примерно такая:
1. Есть Контроллер, который отвечает за перемещение и взаимодействие объектов. Он крутится в отдельном потоке. Вернее, не он целиком, а только один из его методов. Возможно, в этом и проблема. Метод запускается через std::thread(&CController::Execute,m_pCon troller).detach(). detach() потому то при join() все зависало.
2. Есть "Визуализатор", который отвечает за отображение объектов. Его процедуры, отвечающие за отрисовку, вызываются из Контроллера. "Визуализатор" является членом класса Контроллера по специальному интерфейсу.
3. Есть что-то типа пула вспомогательных потоков, (принадлежат классу Контроллера), который занимаются непосредственно расчетами.

В "Визуализаторе" предусмотрен диалог с настройками, по выходу из которого старый Контроллер уничтожается и создается новый экземпляр с новыми настройками.
И вот у меня не получается корректно уничтожить экземпляр Контроллера(((((
В методе, который запускается в потоке, есть булевский флаг, который контролирует цикл
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void CController::Execute()
{
    executeMutex.lock(); // Это попытка как-то исправить ситуацию...
    while (!m_bTerminate)
    {
            m_pView->StartDrawing(); //Сигнал "Визуализатору", что начинается фаза отображения объектов.
//До вызова FinishDrawing  внутри следующих процедур будут вызваться из "Визуализатора" процедуры отрисовки
 
        ManageFlyCycle(); //Здесь запускаются параллельные расчеты в вспомогательных потоках.
                    if (GameMode.eMode == emChase)
        {
            ReLinkInsect();//Определение новых пар для "погони".
            RunWaspCycle();
        }
        else
            TestFlyInfection();
 
        m_pView->FinishDrawing();//Сигнал "Визуализатору", что фаза отображения объектов завершена.
    }
    m_pView->OnControllerTerminate(); //Сигнал "Визуализатору" об уничтожении Контроллера
    executeMutex.unlock(); // Это попытка как-то исправить ситуацию...
}
В класса Контроллер есть метод
C++
1
2
3
4
5
void CController::Terminate()
{
    m_bTerminate = true;
    std::thread([=]() {executeMutex.lock(); executeMutex.unlock();}).detach();
}
который вызывается из "Визуализатора".
Манипуляции с executeMutex - это попытки как-то разобраться/понять, почему изменение флага m_bTerminate не приводит к завершению цикла (не вызывается m_pView->OnControllerTerminate()

Сам проект писан на C++ +wxWidgets. Могу выложить, если нужно.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.09.2023, 14:04
Ответы с готовыми решениями:

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

Прошу подсказки
Ребят помогите. 2 ноутбука, один из них подключен к интернету. Можно ли сделать так чтобы второй ноут подключить через беспроводную сеть к...

прошу подсказки
Доброго времени суток, уважаемые. Прошу подсказать малоопытному. Работаы в IAR AVR 6.20 Задачка - создать во FLASH структуру данных,...

50
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
01.10.2023, 14:48  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Алексей1153 Посмотреть сообщение
this преспокойно захватывается по значению
Да, this нормально захватывается, там был мой косяк)))
В связи с этим вопрос - в поисках косяка я заменил лямбду на вызов метода.
Есть ли здесь принципиальная разница (с учетом того, что нужно захватывать this)?
Или лямбда просто для экономии кода и времени?
0
274 / 206 / 30
Регистрация: 26.11.2022
Сообщений: 908
01.10.2023, 16:07
Цитата Сообщение от Constcat Посмотреть сообщение
почему изменение флага m_bTerminate не приводит к завершению цикла
При работе с многопоточностью всегда делайте явное считывание флагов из памяти. - и лучше через атомарные операции.
Иначе компилятор оптимизирует код и не считывает её из памяти
0
фрилансер
 Аватар для Алексей1153
6510 / 5769 / 1135
Регистрация: 11.10.2019
Сообщений: 15,410
01.10.2023, 18:56
Цитата Сообщение от 4blK4blPblK Посмотреть сообщение
можно было и весь this захватить, но одно поле - экономнее
никакой экономии нет, просто безопасность. Захватили только то, что нужно для работы

Цитата Сообщение от Constcat Посмотреть сообщение
я заменил лямбду на вызов метода.
Есть ли здесь принципиальная разница
лямбда просто удобнее. И оптимизатору тоже удобнее.
А так - на здоровье

Aledveu, а он, что ли, мысленное считывание делает?
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
01.10.2023, 19:30  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
Aledveu, а он, что ли, мысленное считывание делает?
Я предполагаю, что если компилятор видит, что переменная нигде не используется - вызовов метода Execute() (где идет проверка этой переменной) не происходит (метод передается в конструктор std::thread) и в других местах он нигде не вызывается, то считает, что содержимое этой переменной вообще не важно.
0
фрилансер
 Аватар для Алексей1153
6510 / 5769 / 1135
Регистрация: 11.10.2019
Сообщений: 15,410
01.10.2023, 19:39
Constcat, переменная используется
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
01.10.2023, 20:33  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
Constcat, переменная используется
Тогда почему она себя так ведет?
В основном потоке я ей присваиваю значение.
А оно остается старым. В том же потоке.
0
фрилансер
 Аватар для Алексей1153
6510 / 5769 / 1135
Регистрация: 11.10.2019
Сообщений: 15,410
02.10.2023, 06:06
Constcat, либо её содержимое где-то меняется, либо это разные переменные

Добавлено через 13 секунд
код покажи хотя бы
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
02.10.2023, 08:42  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
код покажи хотя бы
Выше три скриншота прикрепил с комментариями.
Уперся в тупик с потоками. Прошу подсказки
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
02.10.2023, 09:22
Constcat, скриншоты, да еще и такие обрывочные - это издевательство.
Нормально код показывайте, текстом и полностью. Там любая мелочь (в том числе та, которую вы считаете мелочью) может иметь значение.
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
02.10.2023, 09:47  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Constcat, скриншоты, да еще и такие обрывочные - это издевательство.
Нормально код показывайте, текстом и полностью. Там любая мелочь (в том числе та, которую вы считаете мелочью) может иметь значение.
У меня код за это время сто раз поменялся.))) Я уже все это давно исправил в соответствии с советами, данными мне в этом треде.
Но если вкратце:
1. Переменная static bool m_bTerminate была объявлена в хедере класса Контроллера.
2. Один из методов этого класса (Execute(), где крутился рабочий цикл с проверкой (m_bTerminate) запускался в фоновом потоке из экземпляра класса Визуализатора.
3. Метод Terminate(), где изменялся флаг m_bTerminate, запускался из Визуализатора в основном потоке.

Схематично это выглядело примерно так:
Хедер класса Контроллер:
C++
1
2
3
4
#pragma once
...
static bool m_bTerminate
...
Реализация (cpp):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
CController::CController(Pview *pView)
{
...
m_bTerminate = false;
...
}
 
CController::Execute()
{
  while (!m_bTerminate)
  {
  //тут крутится то, что должно работать в фоновом потоке
  }
}
CController::Terminate()
{
  m_bTerminate = true;
}
Визуализатор:
C++
1
2
3
4
5
6
7
8
9
10
11
void WaspFlyGLFrm::StartSimulation()
{
m_pController = new CController(this);//this - это Визулизатор.
m_pControllerThread = new std::thread(CController::Execute, m_pController);
//m_pController и m_pControllerThread - члены класса WaspFlyGLFrm
}
void WaspFlyGLFrm::DestroyController()
{
        m_bTerminate = true; //Для эксперимента.
        m_pController->Terminate(); //Terminate() описан выше, там только присвоение флага.
}
Этого кода уже давно нет, я его практически по памяти восстановил.
На скриншотах показано, что при присвоении флагу m_bTerminate = true и входу в метод m_pController->Terminate(), этот же флаг содержит false.

Переменная m_bTerminate - единственная, это 100%. Описана в одном-единственном хедере с #pragma once.
0
фрилансер
 Аватар для Алексей1153
6510 / 5769 / 1135
Регистрация: 11.10.2019
Сообщений: 15,410
02.10.2023, 09:53
Цитата Сообщение от Constcat Посмотреть сообщение
static bool m_bTerminate была объявлена в хедере
.... и во всех единицах трансляции это разные экземпляры теперь.

Кроме того, где синхронизация то?

Добавлено через 33 секунды
Цитата Сообщение от Constcat Посмотреть сообщение
Надеюсь, это std::atomic<bool>
Да.
а ведь обещал

Цитата Сообщение от Constcat Посмотреть сообщение
Переменная m_bTerminate - единственная, это 100%.
внезапно, нет

Добавлено через 1 минуту
вот это, если оно так и будет лежать в хедере на том же месте,
Цитата Сообщение от Constcat Посмотреть сообщение
static bool m_bTerminate
замени на
C++
1
inline std::atomic<bool> m_bTerminate;
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
02.10.2023, 09:57
Цитата Сообщение от Constcat Посмотреть сообщение
У меня код за это время сто раз поменялся.)))
Ну тогда можно считать, что у проблемы нет решения.

С ходу в том, что вы показали, неправильно только что m_bTerminate используется без синхронизации. Это может приводить к "кешированию" значения m_bTerminate, и, соответственно, некорректной работе.

С другой стороны вы выше писали, что пробовали std::atomic в этой роли, что при отсутствии недосказанностей должно было решить проблему. Однако раз оно проблему не решило, значит недосказанности были. А какие они были мы теперь не узнаем. Так что нет, нельзя тут ничего сказать (кроме разве что "используйте гит, чтобы можно было смотреть прежние версии кода в таких ситуациях").

Добавлено через 1 минуту
Цитата Сообщение от Алексей1153 Посмотреть сообщение
. и во всех единицах трансляции это разные экземпляры теперь.
А, так это не переменная класса - static, а глобальный static!
Ну так да, теперь все понятно

Добавлено через 3 минуты
Алексей1153, У меня как-то подобные действия ну никак не смогли ассоциироваться с глобальным static.
Цитата Сообщение от Constcat Посмотреть сообщение
C++
1
2
3
4
CController::CController(Pview *pView)
{
...
m_bTerminate = false;
Тут по всем гласным и негласным правилам напрашивается static в классе.
Еще ведь и m_ написано!
Автор, у меня слов нет
0
фрилансер
 Аватар для Алексей1153
6510 / 5769 / 1135
Регистрация: 11.10.2019
Сообщений: 15,410
02.10.2023, 10:02
DrOffset, да, я бы дал такой переменной имя навроде global_sync_bTerminateControllerThread

Добавлено через 1 минуту
Constcat, при этом, я ж пример даже давал. Без всяких глобальных переменных
Цитата Сообщение от Алексей1153 Посмотреть сообщение
class CController
{
private:
    std::atomic<bool> m_bTerminate{};
    std::thread m_ControllerThread;
public:
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
02.10.2023, 10:09  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
С другой стороны вы выше писали, что пробовали std::atomic в этой роли, что при отсутствии недосказанностей должно было решить проблему. Однако раз оно проблему не решило, значит недосказанности были. А какие они были мы теперь не узнаем.
Да, я понимаю. В любом случае, тот подход был неверным, я все переписал, теперь все работает.
Принципиальные отличия (как мне кажется) старого и нового кода в следующем:
1. Контроллер в Визуализаторе описан, как std::unique_ptr (а не просто указатель на CController)
2. Запуск Execute() в потоке выполняется изнутри класса Контроллера (а не снаружи, из Визуализатора)

Цитата Сообщение от DrOffset Посмотреть сообщение
"используйте гит, чтобы можно было смотреть прежние версии кода в таких ситуациях"
Использую.)))
Но вот такие эксперименты не сохраняю. Я за сутки по несколько раз архитектуру исправляю, с кучей экспериментов.
Когда все это начинаешь сохранять, путаешься что, зачем, нафига и пр.)))))
Фиксирую уже более-менее рабочий вариант.

Добавлено через 3 минуты
Цитата Сообщение от DrOffset Посмотреть сообщение
Тут по всем гласным и негласным правилам напрашивается static в классе.
Я его специально делал глобальным, чтобы точно быть уверенным, что он один.

Цитата Сообщение от DrOffset Посмотреть сообщение
Еще ведь и m_ написано!
Ну так оно по коду встречается. Я экспериментировал, двигал этот флаг туда-сюда, по разным областям. Что, каждый раз нужно было переименовывать по всему коду?)))

Цитата Сообщение от DrOffset Посмотреть сообщение
Автор, у меня слов нет
Ой, можно подумать.)))
В процессе экспериментов и goto можно понапихивать для проверки различных ситуаций.
Понятно, что в финальный вариант оно не попадет)))

Добавлено через 1 минуту
Цитата Сообщение от Алексей1153 Посмотреть сообщение
при этом, я ж пример даже давал. Без всяких глобальных переменных
Не волнуйтесь, я именно так и сделал)))

Просто по просьбе DrOffset, на скорую руку по памяти накарябал образец старого кода.

Добавлено через 1 минуту
Цитата Сообщение от Алексей1153 Посмотреть сообщение
.... и во всех единицах трансляции это разные экземпляры теперь.
Это как?
Я понимаю, что у меня могут быть пробелы в теории, но хедер же включается один раз?
0
фрилансер
 Аватар для Алексей1153
6510 / 5769 / 1135
Регистрация: 11.10.2019
Сообщений: 15,410
02.10.2023, 10:12
Цитата Сообщение от Constcat Посмотреть сообщение
двигал этот флаг туда-сюда, по разным областям. Что, каждый раз нужно было переименовывать
я переименовываю. Во первых, меняется семантика, во-вторых - компилятор тыкнет носом везде, где переменная используется. Чтобы я не забыл осмотреть и подправить все эти места

Цитата Сообщение от Constcat Посмотреть сообщение
но хедер же включается один раз
единиц трансляции таки сколько? Файлов с расширением cpp
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
02.10.2023, 10:14
Цитата Сообщение от Constcat Посмотреть сообщение
Когда все это начинаешь сохранять, путаешься что, зачем, нафига и пр.)))))
Для этого существует branching.

Цитата Сообщение от Constcat Посмотреть сообщение
Фиксирую уже более-менее рабочий вариант
Гит для только этой роли - это как из пушки по воробьям.

Цитата Сообщение от Constcat Посмотреть сообщение
В любом случае, тот подход был неверным, я все переписал, теперь все работает.
Самое важное в работе программиста, как инженера, а не астролога или какого-нибудь таролога, - это четко понимать почему пришлось отказаться от того или иного решения, в чем была ошибка и в чем преимущества нового варианта. Если так не делать, то вся ваша работа будет похожа на череду гаданий на кофейной гуще, где вы в каждый момент времени совершенно не сможете предсказать чем обернется дальнейшая судьба кода. Если вы не будете знать причин и следствий своих решений, то развития в профессиональном смысле тоже никакого не будет. Когда вы столкнетесь с похожей задачей, единственное, что вам останется - это вслепую повторить последний удачный вариант, что сведет на нет всю инженерную сторону вопроса. Почему работает? - не ясно. Почему нельзя иначе? - не ясно. Что ожидает проект после внедрения этого решения? - не ясно. Единственное что вы сможете сказать: "я всегда так делал (с тех пор как путем экспериментов пришел к этому варианту) и проблем не было".

К сожалению слишком часто сталкиваюсь с этими явлениями на практике, чтобы просто промолчать.
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
02.10.2023, 10:14  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
единиц трансляции таки сколько? Файлов с расширением cpp
Ну, для данного флага две. Это хедер подключается к Контроллеру и к Визуализатору.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
я переименовываю. Во первых, меняется семантика, во-вторых - компилятор тыкнет носом везде, где переменная используется. Чтобы я не забыл осмотреть и подправить все эти места
Учту.
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
02.10.2023, 10:15
Цитата Сообщение от Constcat Посмотреть сообщение
Я его специально делал глобальным, чтобы точно быть уверенным, что он один.
Так если он глобальный static и в хэдере, то он с практически стопроцентной вероятностью будет не один. Он будет в каждой из единиц трансляции свой собтвенный.
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
02.10.2023, 10:16  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Самое важное в работе программиста, как инженера, а не астролога или какого-нибудь таролога, - это четко понимать почему пришлось отказаться от того или иного решения, в чем была ошибка и в чем преимущества нового варианта.
Именно поэтому я и продолжаю выяснять, что не так с флагом m_bTerminate, хотя у меня уже все давно работает.
И пробелов в таких случаях я стараюсь не оставлять.
0
фрилансер
 Аватар для Алексей1153
6510 / 5769 / 1135
Регистрация: 11.10.2019
Сообщений: 15,410
02.10.2023, 10:16
Цитата Сообщение от Constcat Посмотреть сообщение
для данного флага две
таким образом, в начале обеих единиц трансляции оказывается определение static чегототам; с внутренним связыванием. Разные экземпляры. У них разный адрес
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
02.10.2023, 10:16

Прошу подсказки
Вот простой код C++: int main() { int ppc= {17,7,18,56,3,64,71,88,91,15,11,115,130,11,20}; int p=0; int w=0; for(w ; w &lt;...

Прошу подсказки и консультации
Поскажите пожалуйста какие таблицы нужно создать для создания базы данных к следующей задаче. Есть офисный комплекс, состоящий из 3-х...

Прошу подсказки новичку
Господа оптимизаторы! Подскажите пожалуйста как правильно раскрутить сайт. Особенно интересует: 1. Запрещены ли дорвеи (о которых...

Прошу подсказки по MVC и соединению с БД
В учебных целях пишу MVC приложение. Уперся в нормальную организацию запросов к базе данных через mysqli Структура каталогов такая:...

Прошу подсказки - определиться с идеологией
С++ builder 10. Подскажите пожалуйста как обычно делают? Собственно задача: Есть данные в таблице их нужно извлечь, показать пользователю,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Программное добавление префикса в нумерацию документов
Maks 27.10.2026
Реализация из решения ниже выполнена в самописной конфигурации на БСП (помощь начинающему коллеге). Задача: Программно добавить префикс в нумерацию документов. Решение: В модуле объекта. . .
После закрытия оутлука продолжает висеть процесс в диспетчере задач
Maks 27.10.2026
С недавнего времени в продакшене возникла проблема: при закрытии оутлука в диспетчере задач продолжал висеть процесс outlook. exe. Проблема возникла после установки MS Office 2021 LTSC на машинах, под. . .
Baragoz - DPS/HPS бот для WoW 3.3.5a, многоязычный
AmbA 26.10.2026
Хотите ещё ботов? У меня есть один! А я пока отдохну от него. https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=12062&stc=1&d=1793007952 Инструкция внутри. https:/ / youtu. be/ VpfFZSUDGnQ. . .
Особенности gif сгенерированных в Си
russiannick 21.10.2026
Рассмотрим генерацию gif файлов, которые в Си имеют свои особенности. Gif представляет собой графический формат популярный в интернете. Посмотрим на палитру. Gif файл сгенерированный в си отличается. . .
FPS контроллер с анимированными Y-Bot и 3D-звуком miniaudio (Box3D, Recast, BehaviorTree.CPP, ozz-animation, ImGui, OpenGL и SDL3)
8Observer8 18.10.2026
Содержание блога | English Version Полное мультиплатформенное руководство по стартовому проекту с FPS-контроллером игрока, анимированными роботами Y-Bot с 4-слойным блендингом, 3D-физикой Box3D,. . .
Локальный http сервер
Argus19 17.10.2026
Локальный http сервер На работе, на двух локальных компьютерах круглосуточно работают программы опроса приборов с записью в книги Excel,которые раз в сутки записываются на сервер компании. Т. к. . . .
Копировать Windows на новый диск на UEFI
damix 17.10.2026
https:/ / uriesk. wordpress. com/ 2016/ 11/ 01/ move-window-10-to-ssd-on-a-uefi-dualboot-system-with-basic-linux-tools/ TL DR Вставляем диск, а старый подключаем через переходник, грузимся с лайва. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru