Fornire un'IO API non bloccante in una libreria C.

4

Sto lavorando su una libreria C ( SlipRock ) per la comunicazione tra processi.

La libreria attualmente espone una semplice API di blocco. Questo è facile da usare, rende l'uso improprio (relativamente) difficile (questo è C dopo tutto) e sarà (relativamente) facile da implementare su più piattaforme, una volta che mi metto a implementare la porta di Windows (che condivide essenzialmente senza codice comune) .

Tuttavia, temo che l'API di blocco possa causare problemi in determinati casi d'uso. Tuttavia, sono molto preoccupato di fornire un'API non bloccante che sia facile da usare e non richiedono l'uso di librerie pesanti come libuv o libevent.

I collegamenti alle lingue che naturalmente fanno pseudo-blocco (blocca il thread verde) I / O (come Go, Erlang o GHC Haskell) possono sempre implementare l'API di livello superiore (o anche l'intero protocollo - non lo è quel complesso) nella lingua di livello superiore. Allo stesso modo, è possibile implementare le parti del protocollo che non sono di tipo blocking (ascolto su un pipe named / socket AF_UNIX e connessione a un socket AF_UNIX, nonché il seguente scambio di password) nella lingua di livello superiore .

Devo fornire un'API C non bloccante o dovrei semplicemente fornire le 2 o 3 funzioni che i collegamenti dovrebbero utilizzare come base per l'API?

Il modo in cui stavo pensando di implementare l'API non bloccante consisteva nel disporre di una macchina a stati che l'utente è tenuto a richiamare manualmente. Ma ciò richiede che l'utente abbia accesso all'impugnatura IO sottostante - che è il valore di ritorno previsto! Quindi ho bisogno di interrompere l'incapsulamento o legarmi a un'implementazione del ciclo degli eventi se voglio esporre un'API asincrona per questo codice non molto performante.

    
posta Demi 20.04.2017 - 00:23
fonte

3 risposte

2

Potresti anche fornire hook specifici per sistemi operativi di basso livello per abilitare (o facilitare) l'IO non bloccante

Ad esempio, per sistemi Linux e POSIX, puoi fornire un modo per ottenere i set di descrittori di file attivi (e lasciare che l'utente chiami sondaggio (2) su di essi, probabilmente fornendo all'utente alcuni ganci per eseguire l'I / O effettivo quando poll rileva l'I / O disponibile) e forse per ricevere una notifica quando quel set sta cambiando. La interfaccia multipla di libcurl potrebbe essere fonte di ispirazione (e forse anche 0mq ). E potresti anche provare a scegliere come target aio (7)

Forse potresti progettare la tua libreria sopra una esistente libreria di eventi (come libevent o libev ).

Non dimenticare di documentare saggiamente gli aspetti asincroni della tua libreria, poiché sono sempre difficili. Puoi anche documentare come usarlo in un'applicazione multithread.

    
risposta data 25.05.2017 - 21:21
fonte
1

Se è necessario fornire un'API non bloccante dipende dalle esigenze degli utenti. Sono d'accordo che forzare gli utenti ad aggiungere una dipendenza a una libreria pesante è una cattiva idea. Puoi inserire l'API non bloccante in una libreria separata.

D'altra parte, non sono d'accordo sul fatto che tu debba interrompere l'incapsulamento. Non conosco i dettagli della tua API, ma sono sicuro che puoi nascondere l'handle del file in qualche modo.

Hai chiesto agli utenti effettivi della tua biblioteca di vedere di cosa hanno bisogno? In caso contrario, perché aggiungere un'API non bloccante?

    
risposta data 25.04.2017 - 18:37
fonte
1

Se vuoi fornire un'interfaccia non bloccante, ci sono solo alcuni modi per farlo:

  1. Incorpora il codice cliente nel tuo ciclo degli eventi.

    Fornisci il tuo loop / dispatcher di eventi. Aggiungi un'interfaccia per il client per aggiungere i propri socket, timeout e callback degli eventi.

    Gestisci il tuo ciclo degli eventi, gestisci il tuo stato asincrono interno, chiama i callback del client quando la loro scrittura slippock è completa, o quando un evento select / poll / any si verifica su un socket che hanno registrato con te

  2. Esporre il tuo FDS al ciclo di eventi del cliente.

    Richiedi al cliente di chiamare il tuo gestore quando succede qualcosa a uno dei tuoi FDS interni.

L'opzione ibrida consente di eseguire il proprio loop di eventi in un thread dedicato che gestisce i socket e lo stato asincrono e comunicare con il codice client tramite una singola socket socket esposta o eventfd che possono eseguire il polling nel loro loop eventi esistente.

Sia nella prima opzione che in quella ibrida, si evita il requisito per il client di richiamare manualmente la macchina di stato.

    
risposta data 26.05.2017 - 10:57
fonte