В то время как асинхронные IO (неблокирующие дескрипторы с select/poll/epoll/kqueue и т.д.) не являются самой документированной вещью в Интернете, есть несколько хороших примеров.
Однако, все эти примеры, определяя дескрипторы, возвращаемые вызовом, имеют только "do_some_io(fd)
" заглушку. Они действительно не объясняют, как наилучшим образом подойти к фактическому асинхронному IO в таком методе.
Блокировка ввода-вывода очень аккуратная и простая для чтения кода. С другой стороны, неблокирование, асинхронное IO, волосатое и грязное.
Какие подходы существуют? Что является надежным и читаемым?
void do_some_io(int fd) {
switch(state) {
case STEP1:
... async calls
if(io_would_block)
return;
state = STEP2;
case STEP2:
... more async calls
if(io_would_block)
return;
state = STEP3;
case STEP3:
...
}
}
или, возможно, (ab) с использованием вычислений GCC:
#define concatentate(x,y) x##y
#define async_read_xx(var,bytes,line) \
concatentate(jmp,line): \
if(!do_async_read(bytes,&var)) { \
schedule(EPOLLIN); \
jmp_read = &&concatentate(jmp,line); \
return; \
}
// macros for making async code read like sync code
#define async_read(var,bytes) \
async_read_xx(var,bytes,__LINE__)
#define async_resume() \
if(jmp_read) { \
void* target = jmp_read; \
jmp_read = NULL; \
goto *target; \
}
void do_some_io() {
async_resume();
async_read(something,sizeof(something));
async_read(something_else,sizeof(something_else));
}
Или, возможно, исключения С++ и конечный автомат, поэтому рабочие функции могут запускать бит abort/resume или, возможно, управляемый таблицей государственный компьютер?
Это не то, как заставить его работать, и как сделать его поддерживаемым, чтобы я гонялся!