Одно из решений, которое я бы назвал типичным, - это «извлечь» из iocb, а затем привести указатель, который вы вернули из io_getevents()
, к вашей структуре.Примерно так:
struct my_iocb {
iocb cb;
void* userdata;
// ... anything else
};
Когда вы выдаете свои задания, независимо от того, выполняете ли вы их по одному или в пакете, вы предоставляете массив структур указателей - iocb
,это означает, что они также могут указывать на my_iocb
.
Когда вы извлекаете уведомления из io_getevents()
, вы просто приводите указатель io_event::obj
к своему собственному типу:
io_event events[512];
int num_events = io_getevents(ioctx, 1, 512, events, NULL);
for (int i = 0; i < num_events; ++i) {
my_iocb* job = (my_iocb*)events[i].obj;
// .. do stuff with job
}
Если вы не хотите блокировать в io_getevents
, а вместо этого получать уведомление через дескриптор файла (чтобы вы могли блокировать в select()
или epoll()
, что может быть более удобно), я бы порекомендовал использовать (без документов) eventfd
интеграция.
Вы можете связать aiocb
с дескриптором файла eventfd с помощью io_set_eventfd(iocb* cb, int fd)
.Всякий раз, когда задание завершается, он увеличивает eventfd на единицу.
Обратите внимание: если вы используете этот механизм, очень важно никогда не читать больше заданий из контекста io (с io_getevents()
), чем счетчик eventfdсказал, что есть, в противном случае вы вводите условия гонки с того момента, когда вы читаете счетчик eventfd и пожинаете задания.