Russian Qt Forum
Апрель 26, 2024, 08:39 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3 4   Вниз
  Печать  
Автор Тема: Корутины (модное слово)  (Прочитано 21989 раз)
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #15 : Сентябрь 26, 2020, 14:08 »

А я не хочу тратить свое время, чтобы объяснять элементарные вещи человеку, которому лень самому разобраться. Я с радостью делал это много раз для джунов, которые еще не умеют что-то самостоятельно выяснять, но ты-то не джун. Подмигивающий Не трать наше время, а иди и сам разбирайся.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #16 : Сентябрь 26, 2020, 14:18 »

Нет никаких ниток, всё в одном потоке делается.
Непонимающий Так быть не должно, это противоречит идее асинхронности

Считайте что co_await делает внутри setjump/longjump в разные куски программы, такой goto. Как оно "у ей внутре" устроено - вопрос отдельный, но логика примерно такая - она как-то сохраняет текущий фрейм и позволяет к нему вернуться.
Ну вот мы запустили корутину и продолжаем выполняться. Нужен longjump чтобы вернуться, но мы же его не пишем сами. Кто (и в какой момент) его аызывает/реализует?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Сентябрь 26, 2020, 14:27 »

А я не хочу тратить свое время, чтобы объяснять элементарные вещи человеку, которому лень самому разобраться. Я с радостью делал это много раз для джунов, которые еще не умеют что-то самостоятельно выяснять, но ты-то не джун. Подмигивающий Не трать наше время, а иди и сам разбирайся.
Лично Вас я не приглашал, и ничего не хочу от Вас получить Улыбающийся Также никаких планов юзать корутины у меня нет, просто интересно что за фишка такая модная и что она делает. Почему мы об этом не можем поговорить? И чего Вы злитесь?  Улыбающийся
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #18 : Сентябрь 26, 2020, 14:40 »

Нет никаких ниток, всё в одном потоке делается.
Непонимающий Так быть не должно, это противоречит идее асинхронности
Что за глупость?
Асинхронность и многопоточность это перпендикулярные понятия, никак не связанные. Может быть асинхронно в одном потоке и синхронно в разных.
« Последнее редактирование: Сентябрь 26, 2020, 19:06 от Old » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #19 : Сентябрь 26, 2020, 14:44 »

Ну вот мы запустили корутину и продолжаем выполняться. Нужен longjump чтобы вернуться, но мы же его не пишем сами. Кто (и в какой момент) его аызывает/реализует?

Компилятор, когда видит co_await. Он выделяет память (в куче) под текущий фрейм сохраняет туда контекст регистры что ему надо и делает setjump.
Когда где-то кто-то зовет handle.resume(), он восстанавливает данные из фрейма и делает переход в корутину (longjump).
Не факт что оно реализуется именно через эти функции, но я других способов не знаю, поэтому мне проще думать в терминах этих функций.
В целом, никто не мешает написать свой джамп, наверное.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #20 : Сентябрь 26, 2020, 14:50 »

Компилятор, когда видит co_await. Он выделяет память (в куче) под текущий фрейм сохраняет туда контекст регистры что ему надо и делает setjump.
Когда где-то кто-то зовет handle.resume(), он восстанавливает данные из фрейма и делает переход в корутину (longjump).
Не факт что оно реализуется именно через эти функции, но я других способов не знаю, поэтому мне проще думать в терминах этих функций.
В целом, никто не мешает написать свой джамп, наверное.
Бэкенд там очень простой, вот на примере ucontext небольшая демка: https://gist.github.com/DanGe42/7148946
В этом примере используются системные сигналы для прерывания сисколов и переключения контекста, но в самом простом случае достаточно одного swapcontext, он все и делает.
« Последнее редактирование: Сентябрь 26, 2020, 14:57 от Old » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #21 : Сентябрь 26, 2020, 14:55 »

Да, вы правы, есть более продвинутый набор функций https://ru.wikipedia.org/wiki/Setcontext
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #22 : Сентябрь 26, 2020, 19:29 »

Ну вот мы запустили корутину и продолжаем выполняться. Нужен longjump чтобы вернуться, но мы же его не пишем сами. Кто (и в какой момент) его аызывает/реализует?

Компилятор, когда видит co_await. Он выделяет память (в куче) под текущий фрейм сохраняет туда контекст регистры что ему надо и делает setjump.
Когда где-то кто-то зовет handle.resume(), он восстанавливает данные из фрейма и делает переход в корутину (longjump).
Не факт что оно реализуется именно через эти функции, но я других способов не знаю, поэтому мне проще думать в терминах этих функций.
В целом, никто не мешает написать свой джамп, наверное.
Вопрос был "кто (и в какой момент)", а не "как" - это действительно технические подробности второго плана. Судя по этому примеру
Код
C++ (Qt)
       while (true) {
           qDebug() << "entering loop";
           co_await qtcoro::make_awaitable_signal(changeTimer, &QTimer::timeout);
           qDebug() << "awaited";
           cr.changeColor();
       }
      ....
Упр-е возвращается на точку "awaited" при выходе (или попытке выхода) из области видимости co_await (тело while). Как если бы co_await вернула какую-то футуру и по окончании итерации while сработал бы ее деструктор. И вот там задача парится до упора и выполняется переход. Др вариантов здесь не видно, больше заставлять main прыгать просто некому. Но меня смущает что это нигде не написано  Плачущий

Понятно что должны быть и др средства для "ручного" упр-я, но тогда co_await должен какую-то цацку вернуть
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #23 : Сентябрь 26, 2020, 19:37 »

Нет, co_await просто делает выход из лямбды сразу же. Он создал объект корутины в куче (для дальнейшего продолжения), сохранил в этот объект контекст и вышел, передав управление обратно в main().
Когда сигнал дернул handle.resume() (смотрите гитхаб как реализован make_awaitable_signal), компилятор восстановил контекст и передал управление на инструкцию следующую за co_await (блин как бесит этот префикс co_, вот нельзя было сделать по-человечески)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #24 : Сентябрь 26, 2020, 20:38 »

Нет, co_await просто делает выход из лямбды сразу же. Он создал объект корутины в куче (для дальнейшего продолжения), сохранил в этот объект контекст и вышел, передав управление обратно в main().
То "first pass"

Когда сигнал дернул handle.resume()..
Вот я и интересуюсь "когда" - само собой это ведь не случится если main продолжил нормальное выполнение после "first pass"

Др словами если main (поток создающий задачи) не блокирован (для этого все и городилось) - то значит он может делать что угодно, и никто "извне" не заставит его сделать переход
« Последнее редактирование: Сентябрь 26, 2020, 20:43 от Igors » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #25 : Сентябрь 26, 2020, 23:05 »

Когда мы создали корутину, мы подписались на сигнал, который дернет resume(). Когда-нибудь. Может быть.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #26 : Сентябрь 27, 2020, 11:08 »

Когда мы создали корутину, мы подписались на сигнал, который дернет resume(). Когда-нибудь. Может быть.
Надеюсь это не "системный" сигнал линуха и не прерывание. А Qt сигналы и все остальное должны получить упр-е. Как оно к ним придет? Тот же фрагмент
Код
C++ (Qt)
      while (true) {
           qDebug() << "entering loop";
           co_await qtcoro::make_awaitable_signal(changeTimer, &QTimer::timeout);
           qDebug() << "awaited";
           cr.changeColor();
       }
 
Везде утверждается (и подчеркивается) что "создатель" (main) "не блокирован". Значит после создания он получит упр-е и перейдет к следующей итерации while.  И что, он будет хрюкать задачи бесконечно? Конечно нет, наоборот, фрагмент намекает что вся возня с таймером замкнута в теле while. Тогда кто инициирует "second pass"? Таймер (когда-то) дернет? А как он получит упр-е? Ведь пока мы крутим while - событийный цикл отрезан.

Здесь неплохо описано, это тот самый случай что Вы говорите. Но это не согласуется с примером выше
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #27 : Сентябрь 27, 2020, 17:09 »

Внимательно посмотрите на вывод который я написал выше. Встретив co_await мы вышли из лямбды и ушли в эвентлуп. Никто не крутит цикл вечно, мы крутимся в эвентлупе пока не придет сигнал от таймера. Когда он приходит, мы возвращаемся в луп, делаем 1 итерацию, и снова выходим в кутешный эвентлуп. И так пока не надоест.
co_await не блокирует (как waitForFinished у QFuture), он отдает управление коду, вызвавшему корутину. На первой итерации это main(), на последующих - сигнал от таймера.
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #28 : Сентябрь 28, 2020, 10:08 »

Цитировать
Типичный пример "бездумного запуска в др потоке" Улыбающийся Если мы все равно "ждем-с", то надо было в main и выполнять, периодически вызывая processEvents, чем кстати и занимается QProgressDialog

Качалка не обязательно умеет сигналы и ивенты. Она может быть блокирующим вызовом, и диалог придется отрисовывать по таймеру.
Вот кстати хороший пример, где не спасет ни processEvents, ни корутина.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #29 : Сентябрь 28, 2020, 18:34 »

Внимательно посмотрите на вывод который я написал выше. Встретив co_await мы вышли из лямбды и ушли в эвентлуп. Никто не крутит цикл вечно, мы крутимся в эвентлупе пока не придет сигнал от таймера. Когда он приходит, мы возвращаемся в луп, делаем 1 итерацию, и снова выходим в кутешный эвентлуп. И так пока не надоест.
co_await не блокирует (как waitForFinished у QFuture), он отдает управление коду, вызвавшему корутину. На первой итерации это main(), на последующих - сигнал от таймера.
Да, так "все сходится", спасибо за разъяснения. Я неверно понял "не блокируется" - стало быть, упр-е возвращается вызывающему. В действительности main пошел заниматься др делами и вернулся только после того как задача выполнена.

Качалка не обязательно умеет сигналы и ивенты. Она может быть блокирующим вызовом, и диалог придется отрисовывать по таймеру.
Вот кстати хороший пример, где не спасет ни processEvents, ни корутина.
В случае "черного ящика" да
Записан
Страниц: 1 [2] 3 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.096 секунд. Запросов: 22.