Здравствуйте, Videoman, Вы писали:
V>Здравствуйте, kov_serg, Вы писали:
_>>_>>int fn_setup(context *ctx,int event_code);
_>>int fn_loop(context *ctx) {
_>> switch(ctx->line) { default:
_>> case 0: /* code 1 */ ctx->line=1; return 1;
_>> case 1: /* code 2 формируем запрос */ ctx->line=2; return 2; // предываемся и просми обработать запрос rc=2 (hint)
_>> case 2: /* code 3 анализируем ответ и был ли он вообще обработан */ ctx->line=3; return 1;
_>> case 3: /* code 4 */ ctx->line=4; return 1;
_>> /*...*/
_>> }
_>> return 0;
_>>}
_>>
V>Спасибо! Примерно то, что меня интересует но такой подход слишком низкоуровневый получается. Если рассматривать такой автомат как корутину, то придется хранить в состоянии всё, в том числе все локальные переменные и руками следить за их временем жизни, если они нужны только нескольким промежуточным состояниям. Больше С++ тут нельзя задействовать как-то?
Можно использовать структуру/класс для хранения состояния. Но тут кстати RAII немного мешает поэтому лучше использовать аналог defer. То есть за ресурсы отвечает не исполнитель, а тот кто выдаёт задаиние исполнителю. В таком случае ресурсы можно контролировать (например ограничивать сверху).
struct Fn1 {
int line;
int i,j,k;
int setup(int sev);
int loop();
static Fn1* my(void* ctx) { return (Fn1*)ctx; }
static int _setup(void *ctx,int sev) { return my(ctx)->setup(sev); }
static int _loop(void *ctx) { return my(ctx)->loop(); }
};
int Fn1::loop() {
LOOP_BEGIN(line)
for(i=1;i<10;i++) {
// ...
LOOP_POINT
// ...
}
LOOP_END()
}
...
Fn1 fn1[1];
Fn1::_setup(fn1,sev_Init);
while( Fn1::_loop(fn1) ) {}
Fn1::_setup(fn1,sev_Done);
Или если больше нравиться можно использовать виртуальные методы, определив общий интерфейс.
struct AFn {
virtual int setup(int)=0;
virtual int loop()=0;
};
Но с функциями гибкость на порядок выше, особенно при использовании внешних динамических библиотек.