2013-01-08 16 views
7

Durante la scrittura di un programma non bloccante (gestione di più socket) che a un certo punto deve aprire i file utilizzando open (2), file stat (2) o directory aperte utilizzando opendir (2), come posso garantire che le chiamate di sistema non vengano bloccate?Accesso non bloccante al file system

Per me sembra che non ci sia altra alternativa all'utilizzo di thread o fork (2).

+0

Non mi aspetterei che sia possibile. Per fare ciò devi fermare tutte le attività del file system nel sistema (per assicurarti che nulla blocchi la tua prossima chiamata a causa di una condizione di competizione tra il tempo che controlli e il tempo in cui chiami effettivamente la funzione), che nessun desktop sane OS ti lascerebbe fare. – Mehrdad

+0

Perché è così importante per te? Nella maggior parte dei casi, un processo sta facendo molto meno "open" syscalls di ad es. 'leggi' e' scrivi', e queste 2 syscalls comuni possono essere non bloccanti!E molto spesso 'open' è abbastanza veloce ... –

+0

Altri sistemi (Windows per uno) in realtà gestiscono questo consentendo di richiedere I/O e quindi ricevere una notifica quando è fatto. Come watain, non ho mai capito come ottenere Linux per farlo bene (+1). – DrC

risposta

2

In effetti non esiste un altro metodo.

In realtà esiste un altro tipo di blocco che non può essere affrontato se non da thread e cioè errori di pagina. Questi possono accadere nel codice del programma, nei dati del programma, nell'allocazione della memoria o nei dati mappati dai file. È quasi impossibile evitarli (in realtà è possibile bloccare alcune pagine in memoria, ma è un'operazione privilegiata e probabilmente si ritorcerà contro rendendo il kernel un cattivo lavoro di gestione della memoria da qualche altra parte). Quindi:

  1. non si può davvero estirpare ogni ultima possibilità di bloccare per un particolare client, in modo da non perdere tempo con artisti del calibro di open e stat. La rete probabilmente aggiungerà ritardi maggiori rispetto a queste funzioni comunque.
  2. Per prestazioni ottimali, è necessario disporre di thread sufficienti in modo che alcuni possano essere programmati se gli altri sono bloccati in caso di errore di pagina o blocco di blocco simile.

Inoltre, se è necessario leggere ed elaborare, elaborare e scrivere dati durante la gestione di una richiesta di rete, è più rapido accedere al file utilizzando il mapping della memoria, ma questo è il blocco e non può essere reso non bloccante. Quindi i moderni server di rete tendono ad attaccarsi alle chiamate di blocco per la maggior parte delle cose e hanno semplicemente abbastanza thread per mantenere la CPU occupata mentre altri thread sono in attesa di I/O.

Il fatto che i server più moderni siano multi-core è un'altra ragione per cui sono necessari comunque più thread.

+0

Ho capito il tuo punto. Peccato che non ci sia la libreria _real_ non-blocking per le operazioni relative al file system (potrebbe rendere le cose più semplici), ma dal momento che non è proprio la stessa cosa con i socket posso capire perché usare i thread è una scelta migliore. – watain

0

È possibile utilizzare il comando poll() per verificare qualsiasi numero di socket per dati utilizzando un singolo thread.

See here for linux details o man poll per i dettagli sul sistema.

open() e stat() sarà bloccare nel thread sono chiamati da tutti i sistemi compatibili POSIX a meno che chiamato tramite una tattica asincrona (come in un fork)

+0

Quindi, come si usa 'poll' per verificare se' open', o 'stat' non avrà bisogno di aspettare che la cache degli inode venga compilata? –

+1

Non è così. Ho letto male la domanda. –

3

Come rispose Mel Nicholson, per descrittore di file tutto quello base è possibile utilizzare select/poll/epoll. Per tutto il resto è possibile avere un thread-per-item proxy (o un pool di thread) con lo small stack che converte (tramite lo scheduler del kernel) qualsiasi blocco sincrono attende di selezionare/poll/epoll-able eventi asincroni usando eventfd o a unix pipe (dove è richiesta la portabilità).

Il thread proxy deve bloccare fino al completamento dell'operazione e quindi scrivere all'evento o alla pipe per riattivare select/poll/epoll.

+0

I file regolari (anche basati sul descrittore) vengono sempre restituiti dal polling. E che i blocchi 'read' in realtà leggono i dati (' write' generalmente non attende la scrittura effettiva su disco, ma potrebbe anche bloccare _reading_ i dati se si sta facendo un accesso casuale) –

+0

@Jan Hudec - then eventfd/kicksocket (pipe) è una strada da percorrere, altrimenti per file ad alte prestazioni di solito viene usato IO mmap, che dà latenze deterministiche – bobah

+0

Non penso che lo sia. Se si effettua ciascuna operazione in modo asincrono separatamente utilizzando il thread di lavoro, il cambio di contesto aggiuntivo aggiungerà un sovraccarico significativo. I thread dovrebbero essere forniti di grossi pezzi di lavoro che possono fare indipendentemente per mantenere la necessità di sincronizzazione ragionevole. –