Лучшие практики для разработки асинхронного c API

Я собираюсь разработать C API для некоторых функций, и я хотел бы сделать его асинхронным, поскольку открытые функции могут занять некоторое время. Использование блокирующего API, вероятно, не является хорошей идеей, поскольку пользователю API нужно будет совершать много одновременных вызовов.

Как правильно спроектировать интерфейс, чтобы я мог уведомить пользователя о завершении асинхронной операции?

Я могу придумать несколько разных подходов, но не могу сказать, что знаю лучшие практики для этого. Есть ли у кого-нибудь опыт работы с подобными API?

В этом примере цель состоит в том, чтобы вернуть целое число, содержащее ответ.

Функция обратного вызова:

typedef void (*callback_function)(int, void *);

/* Calls the callback function with the answer and cookie when done */
error_code DoSomething(callback_function, void *cookie);

Опрос:

error_code DoSomething(void *cookie);

/* Blocks until any call has completed, then returns the answer and cookie */
error_code WaitForSomething(int *answer, void **cookie);

Очередь событий для конкретной платформы

/* Windows version, the api calls PostQueuedCompletionStatus when done */
error_code DoSomething( HANDLE hIoCompletionPort,
                        ULONG_PTR dwCompletionKey,
                        LPOVERLAPPED lpOverlapped );

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

Фьючерсы:

/* External dummy definition for a future */
struct Future_Impl {
    int unused;
};
typedef Future_Impl *Future;

/* Initializes a future, so that it can be waited on later */
error_code DoSomething(Future *future);

/* Blocks until the result is available */
error_code WaitForSomething(Future future, int *answer);

Фьючерсы/события для конкретной платформы:

/* Windows version, the api signals the event when done */
error_code DoSomething( HANDLE hEvent, int *answer );

/* Can be waited on using WaitForMultipleObjects,
   but that has a limit on how many events that can be used */

person villintehaspam    schedule 25.01.2011    source источник


Ответы (2)


Я бы выбрал функцию обратного вызова в качестве основного строительного блока. Я видел, как этот дизайн использовался много раз, и он работает. Указатель void позволяет передать некоторый контекст, в то время как другим параметром обратного вызова обычно является код ошибки. Вы можете создавать другие слои поверх этого, например. конечный автомат, очередь событий или передача объектов синхронизации ОС в контексте.

person Guy Sirton    schedule 26.01.2011

Я понимаю, что вы просили конкретный сценарий, но что касается разработки интерфейсов C, я слышал очень положительные отзывы об этой книге и обычно слышу, что сначала рекомендуется ответить на вопросы, похожие на ваши: C-интерфейсы и реализации: методы создания Многоразовое программное обеспечение

person yan    schedule 25.01.2011
comment
Спасибо за ссылку! Вы случайно не знаете, обсуждается ли вообще асинхронный API? При беглом взгляде на оглавление оказалось, что это не так. - person villintehaspam; 26.01.2011
comment
На вашем месте я бы проверил существующие, хорошо зарекомендовавшие себя асинхронные библиотеки. Попробуйте посмотреть на: monkey.org/~provos/libevent - person yan; 26.01.2011