Я знаю идиому или шаблон для сопрограмм в 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
многопоточность. Мое приложение редко использует поток управления сопрограммой, и использование стека может быть очень большим в многочисленных «потоках», поэтому оно не поддается такой реализации.)
Существует ли повторно используемая реализация в C ++?
Эта статья также говорит о один заголовок, Реализация без стеков, которая находится внутри библиотеки Boost.ASIO.
Еще один ASIO Похоже, что заголовок указывает на то, что они отошли от предыдущего состояния, но я не знаю много об этом. Может быть такой же как последний или нет.
Я реализовал многоразовые стековые сопрограммы некоторое время назад в стандартном 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
Ура, Яркко
Да, он существует, задокументирован и используется в хорошо известном и хорошо распространенном приложении (хотя Putty, но не C ++).
Другая страница об этом использовании устройства Даффа:
Дафф даже прокомментировал это использование, сказав, что он использовал его для конечного автомата, управляемого прерываниями (что сейчас известно под модным словом «Async»):
boost.coroutine не взламывает стек — он использует просто соглашение о вызовах базового соглашения о вызовах (определяемого ABI).
Вы можете сказать, что это просто вызов функции + сохранение / восстановление инструкции и указателя стека.
Локальные переменные сохраняются автоматически.