сопрограммы на основе коммутатора

Я знаю идиому или шаблон для сопрограмм в C и C ++:

struct cofunctor {
int state = 0;

void operator () () {
switch ( state ) {
case 0: // Caller must initialize to 0

if ( bar1 ) return;

while ( bar2 ) {
state = 1; case 1:

if ( bar3 ) return;

state = 2; case 2:

if ( bar4 ) return;
}
state = 3; case 3:
return;
}
}
};

По мере выполнения функции она обновляет постоянную переменную контрольной точки. При следующем вызове значение используется для перехода в середину выполнения. На практике, контрольно-пропускной пункт будет не только int но будет содержать «локальные» переменные.

Я пишу на C ++. Мой вариант использования редко дает результаты, поэтому я хотел бы обновить контрольные точки только во время обработки исключений.

Известна ли эта модель в реальной практике или она задокументирована только как любопытство? Существует ли повторно используемая реализация в C ++?

(Насколько я могу судить, Boost.Coroutine использует несоответствующие хаки стека, мало чем отличается от longjmp многопоточность. Мое приложение редко использует поток управления сопрограммой, и использование стека может быть очень большим в многочисленных «потоках», поэтому оно не поддается такой реализации.)

3

Решение

Существует ли повторно используемая реализация в C ++?

Эта статья также говорит о один заголовок, Реализация без стеков, которая находится внутри библиотеки Boost.ASIO.

Еще один ASIO Похоже, что заголовок указывает на то, что они отошли от предыдущего состояния, но я не знаю много об этом. Может быть такой же как последний или нет.

1

Другие решения

Я реализовал многоразовые стековые сопрограммы некоторое время назад в стандартном C ++, который позволяет вам иметь локальные переменные (определенные как члены классов сопрограмм). Для вызова сопрограммы (я называю это «волокном» в моей реализации) вы сначала инициализируете объект callstack для хранения состояния, а затем запускаете сопрограмму. Вот пример того, как я определяю сопрограмму:

struct fiber_func_test
{ PFC_FIBER_FUNC();
// locals
unsigned loop_count;
// test function
fiber_func_test(unsigned loops_): loop_count(loops_) {}
bool tick(fiber_callstack &fc_, ufloat &dt_)
{
PFC_FIBER_BODY_BEGIN
while(loop_count--)
{
PFC_FIBER_CALL(fc_, dt_, fiber_func_sleep, (0.3f));
}
PFC_FIBER_BODY_END
}
};

loop_count — это локальная переменная, состояние которой хранится в стеке. И вот как это называется:

fiber_callstack fc;
PFC_FIBER_START(fc, fiber_func_test, (10));
while(fc.tick(0.1f))
thread_nap();

Вот ссылка на код: http://sourceforge.net/p/spinxengine/code/HEAD/tree/sxp_src/core/mp/mp_fiber.h

Ура, Яркко

1

Да, он существует, задокументирован и используется в хорошо известном и хорошо распространенном приложении (хотя Putty, но не C ++).

Другая страница об этом использовании устройства Даффа:

Дафф даже прокомментировал это использование, сказав, что он использовал его для конечного автомата, управляемого прерываниями (что сейчас известно под модным словом «Async»):

0

boost.coroutine не взламывает стек — он использует просто соглашение о вызовах базового соглашения о вызовах (определяемого ABI).
Вы можете сказать, что это просто вызов функции + сохранение / восстановление инструкции и указателя стека.
Локальные переменные сохраняются автоматически.

0