await/async от AlexPublic и Coroutine2
От: -MyXa- Россия  
Дата: 13.09.15 15:44
Оценка: 37 (2)
Привет, коллеги!

Я использую вот эту эмуляцию await/async by AlexPublic (правда, вперемешку с замечательными идеями нашего же Евгения. Кастую обоих в эту тему.)

Boost.Coroutine неюзабельна под Windows (в моём случае крэшится GetModuleFileNameW по той же причине).

К счастью, есть библиотека Boost.Coroutine2, которая под Windows может работать через fibers (включается макросом BOOST_USE_WINFIBERS, после чего GetModuleFileNameW перестаёт падать).

Казалось бы, живи, да радуйся, но поведение boost::coroutines::coroutine<void> отличается от boost::coroutines2::coroutine<void> тем, что первая yield-ит в вызвавшую корутину, а вторая — в создавшую!

Т.е. вот у нас две корутины. Первая корутина создаёт вторую. Вторая доходит до своего await-а и идёт отдыхать в GUI очередь. Первая корутина тоже выполняется до await и тоже попадает в очередь. Все спят, кроме главного потока (он к тому времени, кстати, уже сам корутина, потому, что при BOOST_USE_WINFIBERS делается ::ConvertThreadToFiber) — он достаёт первую корутину, которая снова работает до await-а, после чего засыпает! Куда после этого вернётся управление? Варианты:

    1. Управление вернётся обратно в message loop потому, что он и вызывал первую корутину или
    2. Управление вернётся во вторую корутину потому, что она создавала первую.

Как правильно?

Для Boost.Coroutine правильный ответ — первый, для Boost.Coroutine2 — второй.

Вот код — в первой строчке выбирается версия библиотеки. Этот же код в более простом виде (wandbox его почему-то не может слинковать, под Windows — работает).

Вывод для Boost.Coroutine1:

g1g1g1g1g1g2g1g2g1g2g1g2g1g2g1leaving coroutine 1
g2g2g2g2g2leaving coroutine 2


Здесь вызовы корутин (1 и 2) строго чередуются с вызовами g(ui), а после завершения первой — вторая нормально дорабатывает.


Вывод для Boost.Coroutine2:

g1g1g1g1g1g21g1g21g1g1leaving coroutine 1
Assertion `(false)&&("pull_coroutine is complete")' failed.


Здесь видно, что из 2 мы попадали в 1, а после полного завершения первой — срабатывает assert.

Даже если бы не assert — вторая корутина вызывается до того, как поток GUI достанет её из очереди и она себя в очередь кладёт повторно (пока память в очереди не кончится).

Собственно, вопрос, это баг Coroutine2? Если нет, то как с этим поведением бороться?
Если не поможет, будем действовать током... 600 Вольт (C)
Отредактировано 19.09.2015 1:04 -MyXa- . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.