Re[25]: Вопрос по корутинам
От: rg45 СССР  
Дата: 28.08.25 18:27
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>ps: у меня godbolt забанен роскомпозором, только через обходные пути открывается


Так а coliru чем тебе не вариант?

R>>Не-не. Полный текст программы с сылкой на годболт, пожалуйста.

_>https://godbolt.org/z/Tos6MvbeG

Что это? Я вообще ждал варианта, равнозначного этому: https://rsdn.org/forum/cpp/8984074.1
Автор: rg45
Дата: 28.08 12:49
, чтоб можно было сравнивать. А ты с какой целью это демонстрируешь?
--
Справедливость выше закона. А человечность выше справедливости.
Re[26]: Вопрос по корутинам
От: kov_serg Россия  
Дата: 28.08.25 19:34
Оценка:
Здравствуйте, rg45, Вы писали:

R>Что это? Я вообще ждал варианта, равнозначного этому: https://rsdn.org/forum/cpp/8984074.1
Автор: rg45
Дата: 28.08 12:49
, чтоб можно было сравнивать. А ты с какой целью это демонстрируешь?


Вариант без макросов: https://coliru.stacked-crooked.com/a/4c858ba261a0862d

Что именно вы хотите сравнивать?
Re[27]: Вопрос по корутинам
От: rg45 СССР  
Дата: 28.08.25 20:00
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Что именно вы хотите сравнивать?


Здрасьте. О чём мы говорим с самого начала? Ты же заявил
Автор: kov_serg
Дата: 28.08 10:22
, что без корутин "можно спокойно писать точно такой же код. При этом достаточно обычного голого C.". Вот это и сравниваем.

_>Вариант без макросов: https://coliru.stacked-crooked.com/a/4c858ba261a0862d


Ну и? Тебе самому-то нравится то, что ты написал?
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 28.08.2025 20:00 rg45 . Предыдущая версия .
Re[27]: Вопрос по корутинам
От: landerhigh Пират  
Дата: 28.08.25 22:38
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Вариант без макросов: https://coliru.stacked-crooked.com/a/4c858ba261a0862d


Ой (дальше роскомнадзор)

_>Что именно вы хотите сравнивать?


Пишите код так, как будто поддерживать его будет склонный к насилию психопат, который знает, где вы живёте

www.blinnov.com
Re: Вопрос по корутинам
От: ArtDenis Россия  
Дата: 29.08.25 03:19
Оценка: +2
Здравствуйте, LaptevVV, Вы писали:

LVV>А в каких задачах корутины вот прям супер — супер?

LVV>Чего раньше приходилось делать муторно и долго ?

Если посмотреть старые примеры boost::asio, то без поллитры в них не разберёшся. Обратный вызов на обратном вызове сидит и обратным вызовом погоняет. Если посмотреть код с использованием корутин, то он линейный, простой для понимания и легко поддерживаемый. Хотя насчёт последнего можно поспорить
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[28]: Вопрос по корутинам
От: kov_serg Россия  
Дата: 29.08.25 08:22
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здрасьте. О чём мы говорим с самого начала? Ты же заявил
Автор: kov_serg
Дата: 28.08 10:22
, что без корутин "можно спокойно писать точно такой же код. При этом достаточно обычного голого C.". Вот это и сравниваем.


// c++20
std::generator<std::string> runMachine(const int& param) {
    co_yield "Idle";
    co_yield "Started";
    co_yield "Processing";
    while (param < 10)
    {
        co_yield "Waiting";
    }
    co_yield "Stopped";
}

// plain C
int fn1_loop(fn1_t *my) {
    LOOP_BEGIN(my->loop)
    my->value="Idle"; LOOP_POINT
    my->value="Started"; LOOP_POINT
    my->value="Processing"; LOOP_POINT
    while (*my->param < 10) {
        self->value="Waiting"; LOOP_POINT
    }
    my->value="Stopped";
    LOOP_END
}

// C с классами
struct fn1_t {
  int st; const char* value; int &param;
  int loop() {
    LOOP_BEGIN(st)
    value="Idle"; LOOP_POINT
    value="Started"; LOOP_POINT
    value="Processing"; LOOP_POINT
    while (param < 10) {
        value="Waiting"; LOOP_POINT
    }
    value="Stopped";
    LOOP_END  
  }
...

И что грандиозные отличия?

_>>Вариант без макросов: https://coliru.stacked-crooked.com/a/4c858ba261a0862d

R>Ну и? Тебе самому-то нравится то, что ты написал?
А почему мне это должно нравиться? Это должно быть просто, работать и легко объяснимо окружащим (,tp extnf htkbubjpys[ afyfnbrjd)
Re[29]: Вопрос по корутинам
От: rg45 СССР  
Дата: 29.08.25 08:56
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>И что грандиозные отличия?


Мне надоело повторять по сто раз, что я признаю сравнение только полных текстов программ. Ибо для сравнения важны как реализация, так и использование. А ты продолжаешь заниматься ковырянием изюма.

И да, по моим представлениям отличия грандиозные. В одном случае понятный линейный код, в другом — обфусцированная шифровка. Макросы и goto — как вишенка на торте.

Ты думаешь, что если ты налепишь в одной строке объявления переменных, условные операторы, циклы и пр. твой код станет от этого проще? Так напиши вообще всю программу в одну строку без пробелов — сразу у всех выиграешь.

_>А почему мне это должно нравиться? Это должно быть просто, работать и легко объяснимо окружащим (,tp extnf htkbubjpys[ afyfnbrjd)


Ну, приятного аппетита. Что тут ещё сказать.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 29.08.2025 9:12 rg45 . Предыдущая версия . Еще …
Отредактировано 29.08.2025 9:07 rg45 . Предыдущая версия .
Отредактировано 29.08.2025 8:59 rg45 . Предыдущая версия .
Отредактировано 29.08.2025 8:58 rg45 . Предыдущая версия .
Re[30]: Вопрос по корутинам
От: kov_serg Россия  
Дата: 29.08.25 10:55
Оценка:
Здравствуйте, rg45, Вы писали:

R>Мне надоело повторять по сто раз, что я признаю сравнение только полных текстов программ. Ибо для сравнения важны как реализация, так и использование. А ты продолжаешь заниматься ковырянием изюма.

Вы за деревьями не видите леса. Я говорю что концептуально это тоже самое но значительно проще. И доступно еще с 80-х годов.
Но это требует соблюдения некоторых ограничений и требует дисциплины.

R>И да, по моим представлениям отличия грандиозные. В одном случае понятный линейный код, в другом — обфусцированная шифровка. Макросы и goto — как вишенка на торте.

Мдя. Вам шашечи или ехать. Результирующий код ничуть не хуже чем в C++20 и даже лучше. Нет динамической аллокации, состояние явное и может быть сохранено. Количество сущностей на порядок меньше.

R>Ты думаешь, что если ты налепишь в одной строке объявления переменных, условные операторы, циклы и пр. твой код станет от этого проще? Так напиши вообще всю программу в одну строку без пробелов — сразу у всех выиграешь.

На вкус и цвет фломастеры разные. Я объединяю одну логическую операцию на строку и мненя не смущает что она может состоять из нескольких простых операций. Не нравится есть автоформатер.

R>Ну, приятного аппетита. Что тут ещё сказать.

Художника может обидеть каждый. Не каждый может убежать.
Re[28]: Вопрос по корутинам
От: kov_serg Россия  
Дата: 29.08.25 11:48
Оценка: :)
Здравствуйте, landerhigh, Вы писали:

_>>Вариант без макросов: https://coliru.stacked-crooked.com/a/4c858ba261a0862d

L>Ой (дальше роскомнадзор)
Да у меня чтобы попась на godbolt надо обходить блокировки, причем чем дальше тем всё более изощренными способами.

_>>Что именно вы хотите сравнивать?

Вы же тоже использовали C++23, а не C++20 так что там тоже есть изюм для сравнения причем не мало. И если его не видно это не значит что его не надо объяснять другим. Более того в виду сложности концепции понимание её у разных людей может отличаться, что приводит к прикольным спецэффектам.
Я просто предлагаю простую декомпозицию. Асинхронность отдельно, корутины отдельно. Всё явно, без "магии". Легко объяснить, мало сущностей. Реализация доступна без сторонних библиотек на любом компиляторе C или C++. Вообще на любом. То что это может не нравиться эстетам, мы переживём.
Re[5]: Вопрос по корутинам
От: ksandro Мухосранск  
Дата: 29.08.25 12:24
Оценка:
Здравствуйте, so5team, Вы писали:


S>До тех пор пока в отладке не придется разбираться во что превращается каждый co_await, co_return и co_yield.


Ну, это же С++, легкость отладки для слабоков.

S>Из того, что вы описали про "преимущества" stackless-короутин складывается устойчивое ощущение, что все тоже самое было бы еще гораздо проще и удобнее со stackfull-короутинами.



Я писал про корутины вообще. Я соглашусь, что stackfull-короутины удобнее и красивее, и лично я предпочел бы именно их видеть в стандарте.
Но stackfull-короутины можно относительно красиво реализовать без добавления поддержки в языке и вообще есть довольно много вполне годных реализаций в том числе и в Бусте. То есть по идее одно другому не мешает.

S>Где был бы линейный код без мусорных co_, аналогичный тому, чтобы написали бы "в лоб" на голых нитях, но без оверхэда этих самых голых нитей.


Ну, код все-таки не совсем был бы аналогичным, вместо всех этих co_ все равно нужно вызывать yield() везде, где хочешь отдать управление. Отладка кооперативной многозадачности тоже ооочень веселый и увлекательный процесс, как бы она ни была реализована, хотя в любом случае проще чем отлаживать multi-threading.
Re[6]: Вопрос по корутинам
От: so5team https://stiffstream.com
Дата: 29.08.25 12:36
Оценка:
Здравствуйте, ksandro, Вы писали:

K>Ну, код все-таки не совсем был бы аналогичным, вместо всех этих co_ все равно нужно вызывать yield() везде, где хочешь отдать управление.


А зачем?
Прелесть stackfull-короутин в том, что ты пишешь обычный код (как при классическом многопоточном программировании).
А моменты переключения делаются автоматически под капотом функций, которые могут заблокировать выполнение (например, read/write/accept/listen и т.п.).
Re[6]: Отладка многопоточности
От: landerhigh Пират  
Дата: 29.08.25 12:39
Оценка:
Здравствуйте, ksandro, Вы писали:

K>Ну, код все-таки не совсем был бы аналогичным, вместо всех этих co_ все равно нужно вызывать yield() везде, где хочешь отдать управление. Отладка кооперативной многозадачности тоже ооочень веселый и увлекательный процесс, как бы она ни была реализована, хотя в любом случае проще чем отлаживать multi-threading.


Господа, а что вы вкладываете в понятие "отладка (кооперативной многозадачности|многопоточности)" и почему это такая большая проблема? Для друга интересуюсь.
www.blinnov.com
Re[7]: Вопрос по корутинам
От: landerhigh Пират  
Дата: 29.08.25 12:41
Оценка:
Здравствуйте, so5team, Вы писали:

S>Прелесть stackfull-короутин в том, что ты пишешь обычный код (как при классическом многопоточном программировании).

S>А моменты переключения делаются автоматически под капотом функций, которые могут заблокировать выполнение (например, read/write/accept/listen и т.п.).

Которые и должны вызвать этот yield().
Да, весь код по стеку будет выглядеть как самый обычный многопоточный блокирующий код. И ему совершенно не обязательно знать, что он выполняется в контексте корутины. Что есть плюс.

А вот то, что они таки стековые, могут оказаться не просто минусом, а дилбрейкером.
www.blinnov.com
Re[8]: Вопрос по корутинам
От: so5team https://stiffstream.com
Дата: 29.08.25 12:49
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>А вот то, что они таки стековые, могут оказаться не просто минусом, а дилбрейкером.


Когда нет выбора, тогда и нет предмета разговора.
Re[29]: Вопрос по корутинам
От: · Великобритания  
Дата: 29.08.25 13:02
Оценка:
Здравствуйте, kov_serg, Вы писали:

R>>Здрасьте. О чём мы говорим с самого начала? Ты же заявил
Автор: kov_serg
Дата: 28.08 10:22
, что без корутин "можно спокойно писать точно такой же код. При этом достаточно обычного голого C.". Вот это и сравниваем.

_>    co_yield "Processing";
_>    value="Processing"; LOOP_POINT

_>И что грандиозные отличия?
Самое грандиозное отличие, что это first-class штука, поддерживаемая языком. А это значит, что можно это дело легко рефакторить, например, вынести какие-то части в переиспользуемые функции, навигация по коду, отладчик, етс. Или интегрировать с другими фичами языка, например, классы/шаблоны/тд. Хотел бы я взглянуть на то как ты подружишь свои макросы с шаблонами. Хотя, наверное нет, не хотел бы, глаза жалко. Понятно, что из буханки можно сделать троллейбус... но зачем?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[31]: Вопрос по корутинам
От: rg45 СССР  
Дата: 29.08.25 13:10
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Художника может обидеть каждый. Не каждый может убежать.


Намёк понял. Художников больше не нервирую.
--
Справедливость выше закона. А человечность выше справедливости.
Re[9]: Вопрос по корутинам
От: landerhigh Пират  
Дата: 29.08.25 14:07
Оценка:
Здравствуйте, so5team, Вы писали:

L>>А вот то, что они таки стековые, могут оказаться не просто минусом, а дилбрейкером.

S>Когда нет выбора, тогда и нет предмета разговора.

Вот, похоже, именно поэтому в стандарт попали stackless корутины.
www.blinnov.com
Re[30]: Вопрос по корутинам
От: kov_serg Россия  
Дата: 29.08.25 14:14
Оценка:
Здравствуйте, ·, Вы писали:

_>>И что грандиозные отличия?

·>Самое грандиозное отличие, что это first-class штука, поддерживаемая языком. А это значит, что можно это дело легко рефакторить, например, вынести какие-то части в переиспользуемые функции, навигация по коду, отладчик, етс. Или интегрировать с другими фичами языка, например, классы/шаблоны/тд. Хотел бы я взглянуть на то как ты подружишь свои макросы с шаблонами. Хотя, наверное нет, не хотел бы, глаза жалко. Понятно, что из буханки можно сделать троллейбус... но зачем?
За тем постепенно исполняемые функции это тривиальный концепт. А корутины в C++20 это знатный айсберг.

Вот first-class штука для FSM на корутинах. Вот где изюма можно насушить
#include <cassert>
#include <coroutine>
#include <unordered_map>
#include <vector>

#include "gtest/gtest.h"

namespace {

template <typename T> struct generator {
  struct promise_type {
    T current_value;
    using coro_handle = std::coroutine_handle<promise_type>;
    auto get_return_object() { return coro_handle::from_promise(*this); }
    auto initial_suspend() { return std::suspend_always(); }
    auto final_suspend() noexcept { return std::suspend_always(); }
    void return_void() {}
    void unhandled_exception() { std::terminate(); }
    auto yield_value(T value) {
      current_value = value;
      return std::suspend_always{};
    }
  };

  using coro_handle = std::coroutine_handle<promise_type>;
  bool move_next() {
    return handle_ ? (handle_.resume(), !handle_.done()) : false;
  }
  T current_value() const { return handle_.promise().current_value; }
  generator(coro_handle h) : handle_(h) {}
  generator(generator const &) = delete;
  generator(generator &&rhs) : handle_(rhs.handle_) { rhs.handle_ = nullptr; }
  ~generator() {
    if (handle_)
      handle_.destroy();
  }

private:
  coro_handle handle_;
};

struct suspend_tunable {
  bool tune_;
  suspend_tunable(bool tune = true) : tune_(tune) {}
  bool await_ready() const noexcept { return tune_; }
  void await_suspend(std::coroutine_handle<>) const noexcept {}
  void await_resume() const noexcept {}
};

struct resumable_cancelable {
  struct promise_type {
    bool is_cancelled = false;
    using coro_handle = std::coroutine_handle<promise_type>;
    auto get_return_object() { return coro_handle::from_promise(*this); }
    auto initial_suspend() { return std::suspend_always(); }
    auto final_suspend() noexcept { return std::suspend_always(); }
    void return_void() {}
    void unhandled_exception() { std::terminate(); }

    auto await_transform(std::suspend_always) {
      if (is_cancelled)
        return suspend_tunable{true};
      return suspend_tunable{false};
    }
  };

  using coro_handle = std::coroutine_handle<promise_type>;
  resumable_cancelable(coro_handle handle) : handle_(handle) { assert(handle); }
  resumable_cancelable(resumable_cancelable &) = delete;
  resumable_cancelable(resumable_cancelable &&rhs) : handle_(rhs.handle_) {
    rhs.handle_ = nullptr;
  }
  void cancel() {
    if (handle_.done())
      return;
    handle_.promise().is_cancelled = true;
    handle_.resume();
  }
  bool resume() {
    if (!handle_.done())
      handle_.resume();
    return !handle_.done();
  }
  ~resumable_cancelable() {
    if (handle_)
      handle_.destroy();
  }

private:
  coro_handle handle_;
};

struct resumable_noinc {
  struct promise_type {
    using coro_handle = std::coroutine_handle<promise_type>;
    auto get_return_object() { return coro_handle::from_promise(*this); }
    auto initial_suspend() { return std::suspend_always(); }
    auto final_suspend() noexcept { return std::suspend_always(); }
    void return_void() {}
    void unhandled_exception() { std::terminate(); }
  };

  using coro_handle = std::coroutine_handle<promise_type>;
  resumable_noinc(coro_handle handle) : handle_(handle) { assert(handle); }
  resumable_noinc(resumable_noinc &) = delete;
  resumable_noinc(resumable_noinc &&rhs) : handle_(rhs.handle_) {
    rhs.handle_ = nullptr;
  }
  bool resume() {
    if (!handle_.done())
      handle_.resume();
    return !handle_.done();
  }
  ~resumable_noinc() {
    if (handle_)
      handle_.destroy();
  }
  coro_handle handle() {
    coro_handle h = handle_;
    handle_ = nullptr;
    return h;
  }

private:
  coro_handle handle_;
};

using coro_t = std::coroutine_handle<>;

template <typename State, typename Sym> class state_machine {
  State current_;
  std::unordered_map<State, coro_t> states_;
  generator<Sym> gen_;

public:
  state_machine(generator<Sym> &&g) : gen_{std::move(g)} {}

  void run(State initial) {
    current_ = initial;
    states_[initial].resume();
  }

  template <typename F> void add_state(State x, F stf) {
    states_[x] = stf(*this).handle();
  }

  coro_t operator[](State s) { return states_[s]; }

  State current() const { return current_; }

  template <typename F> auto get_awaiter(F transition);

  Sym genval() const { return gen_.current_value(); }
  void gennext() { gen_.move_next(); }
};

template <typename F, typename Sym, typename SM> struct stm_awaiter : public F {
  SM &stm_;
  stm_awaiter(F f, SM &stm) : F{f}, stm_{stm} {}
  bool await_ready() const noexcept { return false; }
  coro_t await_suspend(coro_t) noexcept {
    stm_.gennext();
    auto sym = stm_.genval();
    auto newstate = F::operator()(sym);
    return stm_[newstate];
  }
  bool await_resume() noexcept { return (stm_.genval() == Sym::Term); }
};

template <typename State, typename Sym>
template <typename F>
auto state_machine<State, Sym>::get_awaiter(F transition) {
  return stm_awaiter<F, Sym, decltype(*this)>(transition, *this);
}

}

namespace {

enum class State : char { A, B };
enum class Sym : char { A, B, Term };

using stm_t = state_machine<State, Sym>;

generator<Sym> input_seq(std::string s) {
  for (char c : s) {
    switch (std::tolower(c)) {
    case 'a':
      co_yield Sym::A;
      break;
    case 'b':
      co_yield Sym::B;
      break;
    default:
      co_yield Sym::Term;
      break;
    }
  }

  for (;;)
    co_yield Sym::Term;
}

resumable_noinc StateA(stm_t &stm) {
  auto transition = [](auto sym) {
    if (sym == Sym::B)
      return State::B;
    return State::A;
  };

  for (;;) {
    std::cout << "State A" << std::endl;
    bool finish = co_await stm.get_awaiter(transition);
    if (finish)
      break;
  }
}

resumable_noinc StateB(stm_t &stm) {
  auto transition = [](auto sym) {
    if (sym == Sym::A)
      return State::A;
    return State::B;
  };

  for (;;) {
    std::cout << "State B" << std::endl;
    bool finish = co_await stm.get_awaiter(transition);
    if (finish)
      break;
  }
}

}

TEST(coroutines, fsm) {
  auto gen = input_seq("aaabbaba");
  stm_t stm{std::move(gen)};
  stm.add_state(State::A, StateA);
  stm.add_state(State::B, StateB);
  stm.run(State::A);
  auto Cur = stm.current();
  EXPECT_EQ(Cur, State::A);
}

// crutch for clang on godbolt
#if defined(NOGTESTMAIN)
int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
#endif
Re[10]: Вопрос по корутинам
От: so5team https://stiffstream.com
Дата: 29.08.25 14:19
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>>>А вот то, что они таки стековые, могут оказаться не просто минусом, а дилбрейкером.

S>>Когда нет выбора, тогда и нет предмета разговора.

L>Вот, похоже, именно поэтому в стандарт попали stackless корутины.


ЕМНИП, стековые не стали добавлять потому что их можно реализовать и без внесения изменений в язык, что к тому времени уже неоднократно проделывалось в разных библиотеках. Тогда как для безстековых нужны изменения в языке и поддержка со стороны компилятора. При этом, ЕМНИП в очередной раз, выбранный подход многократно критиковался как во время работы над C++20, так и после его принятия.
Re[7]: Отладка многопоточности
От: kov_serg Россия  
Дата: 29.08.25 14:24
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>Господа, а что вы вкладываете в понятие "отладка (кооперативной многозадачности|многопоточности)" и почему это такая большая проблема? Для друга интересуюсь.

Очень просто потому как многозадачность в c++ не структурированая. Поэтому и отладка превращается в: поймай угря в ведре с угрями.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.