Комментарии 11
Как говорится, стесняюсь спросить:
Для демонстрации корутин на плюсах действительно нужен такой монструозный код?
Как говорил Янычар из фильма "72 метра":
Тут же… можно сломать, пока до конца доберёшься!
Более детально, event1 посылает уведомление до того как receiverThread1 был запущен.
Я не понимаю чем это гарантируется. Также я не понимаю почему нет рейса между if (event.notified), suspendedWaiter.load() и event.suspendedWaiter.store(this)
Я не понимаю чем это гарантируется.
Правильно не понимаете, ничем это не гарантируется. К счастью, код на это не полагается.
Также я не понимаю почему нет рейса между if (event.notified), suspendedWaiter.load() и event.suspendedWaiter.store(this)
Между этими строками нет гонки потому что событие ожидается строго одним потоком, и в этом потоке методы await_ready и await_suspend выполняются последовательно.
Да, вы правы. Теперь вижу: там гонка. Только проблема не в suspendedWaiter.load/store
, а в notified
.
Во-первых, поле notified
не атомарно (точнее, оно объявлено как атомарное, но используется почему-то по-другому). Во-вторых, работа с notified
и с suspendedWaiter
неатомарна в целом (атомарность не компонуется).
Правильный вариант должен использовать всего одно поле, CAS-операции и синтетическое значение для состояния notified. Должно получиться как-то так (на современных плюсах не писал, прошу простить ошибки):
// class Event
constexpr Awaiter * NOTIFIED = (Awaiter*)(void*)(1);
std::atomic<Awaiter *> state;
void Event::notify() {
auto *waiter = state.exchange(NOTIFIED);
if (waiter != nullptr && waiter != NOTIFIED) {
waiter->coroutineHandle.resume();
}
}
bool Event::Awaiter::await_ready() const {
return false;
}
bool Event::Awaiter::await_suspend(std::coroutine_handle<> ch) {
Awaiter *expected = nullptr;
return event.state.compare_exchange_strong(&expected, this);
}
coro.destroy();
RAII в C++ — всё?
Она есть в cppcoro: https://github.com/lewissbaker/cppcoro#generatort
Корутины в C++20. Часть 2