C 20 сопрограмм, стандартный тип возврата и сохранение состояния

#c #c 20 #c -standard-library #c -coroutine

#c #c 20 #c -стандартная библиотека #c -сопрограмма #c -сопрограмма

Вопрос:

Этот вопрос на самом деле состоит из двух вопросов. Я спрошу их сразу, потому что они могут быть связаны.

Я только что впервые взглянул на сопрограммы C 20. Если вы видели различные примеры, большинство из них довольно простые. Например, следующее:

 generator<int> ints(int x)
{
   for (int i = 0; i < x;   i)
   {
      co_yield i;
   }
}
  

Во всех примерах используется специальный возвращаемый тип, который, очевидно, содержит результат вычисления плюс контекст сопрограммы. Однако ни в одном примере не используется стандартный возвращаемый тип. Они либо незаметно опускают этот тип, либо определяют пользовательский вложенный класс, который трудно понять (для меня, в настоящее время).

1. Означает ли это, что стандартная библиотека C 20 не предоставляет типы возвращаемых сопрограмм, которые готовы к использованию, например, для генератора?

Лучшее, что я смог найти std::coroutine_handle , это то, что внутренне используется упомянутыми пользовательскими классами.

В документах говорится, что сопрограммы являются хорошим инструментом для реализации алгоритмов, которые требуют поэтапной обработки данных и обычно должны быть разделены на фрагменты, например, с использованием (потенциально ужасно сложного) механизма состояний. Я тоже это понимаю. Я даже помню какой-то проект, который был бы отличным вариантом использования для сопрограммы, а именно загрузка большого сложного XML-файла с использованием потокового интерфейса.

Тем не менее, кажется, есть большая разница: при реализации механизма состояний довольно легко сохранять и загружать состояние на / с диска, поскольку все данные о состоянии доступны как стандартные переменные (достаточно некоторой проверки ошибок и обработки файлов). Я думаю о чем-то вроде пользовательского интерфейса для отмены / возобновления длительных вычислений.

2. Существует ли (простой) способ сохранения / загрузки контекста сопрограммы в / из постоянного хранилища? Есть ли что-нибудь в стандарте C 20, что помогает в этом?

Ответ №1:

  1. Означает ли это, что стандартная библиотека C 20 не предоставляет типы возвращаемых сопрограмм, которые готовы к использованию, например, для генератора?

Это не так. В то время как в технической спецификации предлагались все основные положения о том, как вы можете сделать тип совместимым с сопрограммой, ни в ней, ни в какой-либо из ее редакций не предлагались какие-либо стандартные типы, совместимые с сопрограммой.

Он предоставил по крайней мере одну игрушечную реализацию генератора, которую можно было бы использовать с небольшой настройкой.

p2168 формально предлагает std::generator тип, который будет использоваться в сопрограммах. Вы также можете ознакомиться с библиотекой cppcoro Льюиса Бейкера.

  1. Существует ли (простой) способ сохранения / загрузки контекста сопрограммы в / из постоянного хранилища?

Короткий ответ — «нет».

Есть ли что-нибудь в стандарте C 20, что помогает в этом?

Короткий ответ также «нет».

Когда сопрограмма создается, компилятор выделяет некоторое пространство в куче для контекста сопрограммы, включая локальные переменные и копии / ссылки на параметры. Не совсем в отличие от того, как существуют стековые фреймы для вызовов функций. Но мы же не сериализуем фреймы стека, не так ли? Это не совсем имеет смысл.

Подумайте об этом так: если бы вы хотели сериализовать обычную функцию, вы бы превратили ее в объект. Как это делает шаблон команды. Результат не совсем похож на фрейм стека, но у вас все равно есть что-то для вызова, что делает то, что вам нужно.

Сопрограммы ничем не отличаются. Если вам нужно сериализовать / десериализовать состояние, вы должны использовать вызываемый объект. Вы могли бы использовать этот объект внутри сопрограммы, но это было бы не совсем то же самое.

Ответ №2:

В C 20 нет библиотечных функций или типов сопрограмм, за исключением дескрипторов и признаков на уровне реализации. Вам нужна библиотека сопрограмм, которую вы можете создать самостоятельно или использовать из существующего источника, такого как cppcoro.

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

Комментарии:

1. Я не уверен, что на самом деле возможно сериализовать / десериализовать контекст сопрограммы. По крайней мере, все, что будет десериализовано, не будет ожидаемой сопрограммой.

2. Вы могли бы написать, например, генератор, который разрешал бы сериализацию и возобновлял генерацию с той же точки в последовательности при десериализации.

3. Согласен. Генератор в этом случае будет типом, поддерживающим сопрограмму (предоставляющим необходимые функции и признаки типа для использования в co_yield / await / return ). Включение сериализации для его состояния определенно имело бы свое применение. ОП спросил о сериализации контекста сопрограммы, что для меня звучало как сериализация состояния сопрограммы, выделенного в куче. В стандарте нет формального определения «контекста сопрограммы», только контекст приостановки, который в основном является телом функции (везде, где может появиться выражение ожидания), поэтому я приравнял их.