| Название: waitForDone Отправлено: Igors от Июня 23, 2021, 09:27 Добрый день Создал QThread (рабочую) и подбрасываю ей работу сигналами из главной нитки, все устраивает. Но в какой-то момент главная должна дождаться что у рабочей нет больше задач. Др словами нужен ф-ционал QThreadPool::waitForDone но для конкретной рабочей нитки. Как это сделать технично, не влезая в очереди, примитивы синхронизации и.т.п. ? Спасибо Название: Re: waitForDone Отправлено: Racheengel от Июня 29, 2021, 15:56 То есть надо дождаться завершения QThread ? Для этого есть сигнал QThread::finished() Название: Re: waitForDone Отправлено: Igors от Июня 29, 2021, 16:28 То есть надо дождаться завершения QThread ? Для этого есть сигнал QThread::finished()То есть нет, завершать рабочую никто не хотел (QThreadPool мы же не завершаем). WaitForDone должна вернуть упр-е когда рабочая не имеет больше задач и ожидает их (в своем exec) Название: Re: waitForDone Отправлено: Racheengel от Июня 30, 2021, 15:44 Ну, тогда свой сигнал сделать, и бросать его, если задач нет. Какая-то призрачная проблема, если честно. Название: Re: waitForDone Отправлено: Igors от Июня 30, 2021, 17:13 Ну, тогда свой сигнал сделать, и бросать его, если задач нет.Какой сигнал и как (или куда) его бросать? Кароч, "а можна пример"?  :) Какая-то призрачная проблема, если честно. Название: Re: waitForDone Отправлено: RedDog от Июля 01, 2021, 14:36 Код: void ThreadWrapper::threadFunc() Название: Re: waitForDone Отправлено: Igors от Июля 02, 2021, 06:06 Код: void ThreadWrapper::threadFunc() Вот. Теперь (стартовый пост) надо дождаться когда рабочая нитка сделает все свои текущие дела - не путать с завершением. Название: Re: waitForDone Отправлено: Racheengel от Июля 02, 2021, 16:09 Код: 
 Внешний цикл крутится, пока кто-то не запросит interruption. Пока есть чего делать, делаем doWork(). Как только работа закончилась, "пуляем" nothingToDo() и зависаем в "пустышке", пока снова работы не подвалит. Чтоб ресурсы не жрались, делаем sleep/msleep (это важно, а то потог будет ждат около 10% проца впустую). Название: Re: waitForDone Отправлено: Igors от Июля 03, 2021, 08:50 Как это сделать технично, не влезая в очереди, примитивы синхронизации и.т.п. ?А предлагая hasSomethingToDo мы признаем что очередь имеем/храним, а это не так уж мало еще кода. Вообще зачем использовать свой run вместо exec по дефаулт?  В чем "выйгрышь"? Испускание notingToDo некорректно, в этот (злополучный) момент главная как раз посылает новую работу, просто рабочая ее еще не увидела. Корявый (m)sleeo тоже "не украшает". И как из главной дождаться момента "нет работы"? Требуется синхронка, а не отлов сигнала (к тому же неверного). Название: Re: waitForDone Отправлено: RedDog от Июля 03, 2021, 19:06 Код: void ThreadWrapper::threadFunc() Вот. Теперь (стартовый пост) надо дождаться когда рабочая нитка сделает все свои текущие дела - не путать с завершением. ThreadWrapper::moveToThread в конструкторе и будет постоянно крутиться в отдельном своем потоке. А ThreadWrapper::threadFunc() это либо слот, либо через invokeMethod его дернуть в своем потоке. Название: Re: waitForDone Отправлено: Igors от Июля 04, 2021, 11:34 С чего вдруг перезапускать?Опять-таки, требуется (синхронное) ожидание, а не сигнал. Но главное - такая конструкция не будет работать корректно. Пожуем ThreadWrapper::moveToThread в конструкторе и будет постоянно крутиться в отдельном своем потоке. А ThreadWrapper::threadFunc() это либо слот, либо через invokeMethod его дернуть в своем потоке. Код: while (!done) // while (hasSomethingToDo()) И снова - не вижу откуда взять "done" не связываясь с (хлопотливой) очередью. Название: Re: waitForDone Отправлено: ssoft от Июля 05, 2021, 09:21 Строго говоря, аналогом QThreadPool::waitForDone является QThread::wait. Здесь же требуется дождаться выполнения всех задач в потоке. Возможно, так получится подождать. Сам не пробовал). Код 
 Название: Re: waitForDone Отправлено: RedDog от Июля 05, 2021, 09:28 Опять-таки, требуется (синхронное) ожидание, а не сигнал.std::async PS: ожидание асинхронной задачи с остановкой потока - проблемы в архитектуре (мое имхо) Название: Re: waitForDone Отправлено: Racheengel от Июля 05, 2021, 13:49 PS: ожидание асинхронной задачи с остановкой потока - проблемы в архитектуре (мое имхо) Вот у меня тоже закрались подобные подозрения. Зачем вообще главному потоку знать, что воркеру "делать нечего", в чем суть задачи? Балансирование загрузки? Так нет, судя по всему, воркер только один. Пусть главный поток сам следит о том, что он на обратку отдал. Воркер почему этим заниматься то должен?? Название: Re: waitForDone Отправлено: Igors от Июля 05, 2021, 18:06 Строго говоря, аналогом QThreadPool::waitForDone является QThread::wait.Ну никак не "строго", о (затратном) завершении речь не идет. А предложение processEvents - это куча побочных эффектов (лекарство хуже болезни) std::asyncИ сразу дустом в рыло :) PS: ожидание асинхронной задачи с остановкой потока - проблемы в архитектуре (мое имхо) Вот у меня тоже закрались подобные подозрения.Ага, стандартное "плохая задача". Заметим что точно такой же ф-ционал QThreadPool::waitForDone почему-то не вызывает никаких вопросов. Типовое использование Зачем вообще главному потоку знать, что воркеру "делать нечего", в чем суть задачи? Балансирование загрузки? Так нет, судя по всему, воркер только один. Пусть главный поток сам следит о том, что он на обратку отдал. Воркер почему этим заниматься то должен?? Код Накидал задач и жду пока все сварится. Считать это "плохой архитектурой" нет оснований. Синхронка не есть "плохо", она менее гибка, но есть масса ситуаций когда нельзя связываться с др событиями пока данная (крытыческая) часть кода не завершена. Поэтому иногда ожидание неизбежно/необходимо. А сколько рабочих ниток (одна или N) - чисто специфика задачи. Ну и вообще - неужели это такая страшная задача которой надо изо всех сил избегать? :) Напр есть простецкое решение: - завести атомарный счетчик. напр m_taskСount. Главная (посылающий) его инкрементирует, рабочая наоборот, декрементирует. Тогда Код Кстати как оформить чище, без sleep? Одно время народ увлекался всякими "футурами", может применить? Или то просто была "дань моде"? :) Потом увидел еще решение. В раннем детстве смотрел фильм "про шпионов", запомнился эпизод Цитировать - Вот она прислала письмо, пишет что все норм. Прочитать?Думается здесь такой приемчик проходит. А может еще есть решения? Думать бум? Или только молиться на великий дуст и.т.п. ? :) - Не надо, если все норм она должна была прислать чистый лист бумаги Название: Re: waitForDone Отправлено: Racheengel от Июля 06, 2021, 10:46 Ну, архитектуры тут нету, это чисто вопрос дизайна приложения. Да, "плохая задача", инфа 99% :) Поскольку это "главный" поток, подвешивать его в цикле - это моветон. Задайте себе вопрос: а почему, собственно, он должен ждать? Что происходит в момент ожидания? Что видит юзер в этот момент? Прогресс бар или спиннер? В этом случае надо бы события обрабатывать. Если же так прямо надо подвеситься, то проще всего решается поллингом воркера. Типичное не модное, но рабочее решение "без зауми". Название: Re: waitForDone Отправлено: Igors от Июля 06, 2021, 12:53 Если же так прямо надо подвеситься, то проще всего решается поллингом воркера. Типичное не модное, но рабочее решение "без зауми". "А я шо делаю?" (как говорят в моем регионе). while m_TaskCount и есть поллинг. Но все-таки sleep - это моветон. Где все эти прелести std:: которые якобы "тупо лучше" ? Макс, где Ваш "вариант с футурами"? :) Кстати, "контроль кода" в Вашей компании пропустит sleep в цикле ? Поскольку это "главный" поток, подвешивать его в цикле - это моветон.Ну это рекомендации что даются другим, сам дающий следовать им не будет :) Ну вот хотя бы отмена фоновой операции. Да, выставил флажок abort для воркера, но дождаться обязан, рыпаться с др событиями пока ресурс(ы) захвачен воркером - себе дороже Задайте себе вопрос: а почему, собственно, он должен ждать? Что происходит в момент ожидания? Что видит юзер в этот момент? Прогресс бар или спиннер? В этом случае надо бы события обрабатывать. Название: Re: waitForDone Отправлено: RedDog от Июля 06, 2021, 13:44 С применением std & boost, но принцип будет понятен: Код: std::string fullConfig; Название: Re: waitForDone Отправлено: m_ax от Июля 06, 2021, 15:10 Цитировать Синхронка не есть "плохо", она менее гибка, но есть масса ситуаций когда нельзя связываться с др событиями пока данная  (крытыческая) часть кода не завершена. Поэтому иногда ожидание неизбежно/необходимо. А сколько рабочих ниток (одна или N) - чисто специфика задачи.Да, согласен, в некоторых специфичных задачах это может иметь место. Кстати, недавно же обсуждали подобную проблему: http://www.prog.org.ru/topic_32489_0.html (http://www.prog.org.ru/topic_32489_0.html). Сошлись на том, что thread_pool оптимальное решение) + wrapper_pool) Название: Re: waitForDone Отправлено: Racheengel от Июля 06, 2021, 19:03 Ну это рекомендации что даются другим, сам дающий следовать им не будет :) Ну вот хотя бы отмена фоновой операции. Да, выставил флажок abort для воркера, но дождаться обязан, рыпаться с др событиями пока ресурс(ы) захвачен воркером - себе дороже Почему же, "сам так делал". Именно что диалог показывал, где прогресс бар и кнопка отмены была. В диалоге ждал, пока воркер или отработает, или отвалится по кнопке. Ну вернее как ждал, это QProgressDialog ждал, но он то модальный. Нажал юзер кнопку - шлем воркеру отмену и когда отменил, то прячем диалог. Название: Re: waitForDone Отправлено: Racheengel от Июля 06, 2021, 19:06 Кстати, "контроль кода" в Вашей компании пропустит sleep в цикле ? А что не так со слипом в цикле? Слип останавливает поток на некоторое время, ресурсы проца не жрутся. Не вижу, почему это плохо :) Название: Re: waitForDone Отправлено: RedDog от Июля 06, 2021, 19:29 А что не так со слипом в цикле? Слип останавливает поток на некоторое время, ресурсы проца не жрутся.Потому что поток стоит, а мог бы работать. Да и проц нечего экономить, пусть трудится. Не вижу, почему это плохо :) Название: Re: waitForDone Отправлено: Racheengel от Июля 06, 2021, 23:51 Потому что поток стоит, а мог бы работать. Да и проц нечего экономить, пусть трудится. Ну поток не грузовик, он когда не работает, дорогу не занимает) Тем более в это время другие потоки шуруют во всю, если надо. Название: Re: waitForDone Отправлено: RedDog от Июля 07, 2021, 09:17 Потому что поток стоит, а мог бы работать. Да и проц нечего экономить, пусть трудится. Ну поток не грузовик, он когда не работает, дорогу не занимает) Тем более в это время другие потоки шуруют во всю, если надо. Название: Re: waitForDone Отправлено: Igors от Июля 07, 2021, 10:59 ...в некоторых специфичных задачах это может иметь место.Опять интересно наблюдать разницу между собственными решениями и раздаваемыми рекомендациями  :) Помнится сами Вы ждали на мешке футур и ни о какой "асинхронке" и не помышляли. Почему же, "сам так делал". Именно что диалог показывал, где прогресс бар и кнопка отмены была. В диалоге ждал, пока воркер или отработает, или отвалится по кнопке.Да, в моей практике этот вариант тоже самый популярный. Но разве это "честная" асинхронка? Нет, события выполняются лишь для модального окна (индикатор прогресса). Это модальная задача, а вовсе не фоновая. И это нормально, обычно др выхода просто нет. В фоне хорошо файл качать который самому не нужен (во всяком случае пока). А если обновляются активные, рабочие данные, отображаемые в UI - какой там нафиг "фон", все сразу рухнет Ну вернее как ждал, это QProgressDialog ждал, но он то модальный. Нажал юзер кнопку - шлем воркеру отмену и когда отменил, то прячем диалог. Кстати есои мы уж так идейны/принципиальны - то давайте заодно рассмотрим и асинхронный вариант, для него ведь тоже решений не видно (пока) Название: Re: waitForDone Отправлено: RedDog от Июля 07, 2021, 11:19 Кстати есои мы уж так идейны/принципиальны - то давайте заодно рассмотрим и асинхронный вариант, для него ведь тоже решений не видно (пока) Код: void MainThreadWorker::onFinishShadowThread() Название: Re: waitForDone Отправлено: Igors от Июля 07, 2021, 11:27 А что не так со слипом в цикле? Слип останавливает поток на некоторое время, ресурсы проца не жрутся.Да, но так мы расписываемся типа "я маленький, сделать нормально не могу, вот сделал кое-как, не бейте". Но мы же не такие, правда?  :) Не вижу, почему это плохо :) Если "чисто объективно" то уязвимое место - сколько ms? Очевидно что если потребуется "выжвть все" то sleep не годится. Словом, неполноценное и малодушное рещение Название: Re: waitForDone Отправлено: Igors от Июля 07, 2021, 12:12 С применением std & boost, но принцип будет понятен:Вот я хочу работать так Типовое использование Лично мне это кажется разумным и удобным. Наделал сигналов, связал их с воркером, и просто посылаю "по ходу дела", знать не знаю ни о каких очередях, синхронизации и.т.п. Параметры задачи передаю прямо в аргументах сигнала, остальное сделает Qt. Код Накидал задач и жду пока все сварится И тут .. Код: std::string fullConfig; Ну ладно, попробуем разобраться. Опять та же непонятка: как Вы собираетесь "подкидывать задачи по ходу дела"? Я просто сигналами, а Вы? Какой-то fullConfig, откуда его брать - хз. Вообще, насколько это "адекввтно"? Нужны ли такие средства для решения задачи что выглядит весьма скромно? (waitForDone) Название: Re: waitForDone Отправлено: RedDog от Июля 07, 2021, 13:17 Ну ладно, попробуем разобраться. Опять та же непонятка: как Вы собираетесь "подкидывать задачи по ходу дела"? Я просто сигналами, а Вы? Какой-то fullConfig, откуда его брать - хз. Я просто скопипастил кусок своего кода и рабочего проекта. Буст там исключительно для асинхронности (от Qt отказываемся). Вообще, насколько это "адекввтно"? Нужны ли такие средства для решения задачи что выглядит весьма скромно? (waitForDone) Смысл в том, чтобы запустить параллельную задачу, встать на wait_condition и ждать пока в лямбде этот wait_condition не занатифает кто либо из параллельного потока. Замените бустовый контекст на QThread а лямбду на слот, и получится то же самое. upd: нашел еще один проект, с похожей асинхронкой, почистил от всего лишнего, может натолкнет на мысли Название: Re: waitForDone Отправлено: Igors от Июля 07, 2021, 13:49 Смысл в том, чтобы запустить параллельную задачу, встать на wait_condition и ждать пока в лямбде этот wait_condition не занатифает кто либо из параллельного потока.Это понял, но тогда надо засисять доступ к fullConfig (по сути очередь), а делать это обычно неудобно, напр очередь пуста, но последняя задача еще тикает. Конечно охаять чужой код - много ума не надо, но впечатление что с "современным С++" забот заметно больше - и очередь (аналог), и примитив синхронизации - все то чего хотелось избежать :) Да, а "послать чистый лист бумаги" - так никто и не допер? :'( Не может быть, наверное это просто "слишком очевидно" :) Название: Re: waitForDone Отправлено: RedDog от Июля 07, 2021, 22:11 Смысл в том, чтобы запустить параллельную задачу, встать на wait_condition и ждать пока в лямбде этот wait_condition не занатифает кто либо из параллельного потока.Это понял, но тогда надо засисять доступ к fullConfig (по сути очередь), а делать это обычно неудобно, напр очередь пуста, но последняя задача еще тикает. Конечно охаять чужой код - много ума не надо, но впечатление что с "современным С++" забот заметно больше - и очередь (аналог), и примитив синхронизации - все то чего хотелось избежать :) Да, а "послать чистый лист бумаги" - так никто и не допер? :'( Не может быть, наверное это просто "слишком очевидно" :) Название: Re: waitForDone Отправлено: Igors от Июля 08, 2021, 05:18 вместо условия !fullConfig.empty() можно завести свой булевый флаг в фоновом треде, который будет означать отсутствие активных задач.Воркер четко знает что задача завершена (он ее выполнял), но не может поручиться за отсутствие, ведь задачи посылаются главной. Парить атомарный счетчик (++ в главной, -- в воркере) - да, есть такой вариант, неплохой, позволяет работать чисто сигналами. Второй вариант в духе "анти-велик", использование Qt инструментария Код Слот пустой, но он получит упр-е после всех предыдущих сигналов, т.е. когда желанный "done" наступил. Ну и легким движением руки это превращается в асинхронку. Не умаляя заслуг std/boost замечу что потребности в них здесь никакой Название: Re: waitForDone Отправлено: RedDog от Июля 08, 2021, 09:45 Следующим этапом может быть use-case когда надо подождать, но какое то конечное время.  С пустым сигналом просто будет deadlock на все приложение если фоновый поток заблокируется. Ну мало ли, из сети что то не пришло, или файла какого нибудь на месте не оказалось. Название: Re: waitForDone Отправлено: Igors от Июля 08, 2021, 13:09 Следующим этапом может быть use-case когда надо подождать, но какое то конечное время. Резонный запрос. Я бы делал так С пустым сигналом просто будет deadlock на все приложение если фоновый поток заблокируется. Ну мало ли, из сети что то не пришло, или файла какого нибудь на месте не оказалось. Код 
 |