2009-02-27 14 views
21

Per semplificare, questa è una situazione in cui un server NamedPipe sta aspettando un CLIENT NamedPipe per scrivere al tubo (utilizzando WriteFile())rottura ReadFile() blocco - denominato pipa (API Windows)

API Windows che sta bloccando è ReadFile()

il Server ha creato il tubo sincrona (non sovrapposto I/O) con il blocco abilitato

il client è connesso, e ora il server è in attesa di alcuni dati.

Nel normale flusso di cose, il client invia alcuni dati e il server lo elabora e quindi ritorna a ReadFile() per attendere il prossimo pezzo di dati.

Nel frattempo si verifica un evento (input utente per esempio) e NamedPipe SERVER deve ora eseguire un altro codice, che non può eseguire mentre il ReadFile() sta bloccando.

A questo punto devo dire che il Client NamedPipe non è la mia applicazione, quindi non ne ho il controllo. Non riesco a inviare alcuni byte per sbloccare il server. Sta semplicemente seduto lì e non invia dati. Dal momento che non ho il controllo dell'implementazione del Cliente, non posso cambiare nulla a tale scopo.

Una soluzione potrebbe essere quella di creare un thread separato in cui vengono eseguite tutte le operazioni di ReadFile(). In questo modo quando si verifica l'evento, posso solo elaborare il codice. Il problema è che l'evento richiede anche un thread separato, quindi ora ho due thread aggiuntivi per ogni istanza di questo server. Dal momento che questo deve essere scalabile, questo non è desiderabile.

da un altro thread ho provato a chiamare

DisconnectNamedPipe() 

e

CloseHandle() 

entrambi non tornerà (finché il client scrive al tubo.)

Non riesco a collegarmi alla stessa pipa e scrivere alcuni byte perché:

"Tutte le istanze di un nome pipe condivide lo stesso nome pipe, ma ogni istanza ha propri buffer e handle e fornisce un conduit separato per la comunicazione client/server ".

http://msdn.microsoft.com/en-us/library/aa365590.aspx

Ho bisogno di un modo per fingere fuori, così il $ 64k domanda di dollari è:

Come posso rompere il blocco di ReadFile()?

risposta

1

Il problema con questo, è che l'evento richiede anche un thread separato, così ora hanno due fili aggiuntivi per ogni istanza di questo server. Poiché questo deve essere scalabile, questo non è desiderabile.

Mai nella mia carriera ho trovato che "più discussioni" == "meno scalabile". Quante di queste istanze "server" hai?

In genere, è necessario eseguire un'operazione in un thread separato se tale operazione sta per bloccarsi e il sistema deve essere reattivo mentre l'operazione è bloccata.

+0

Quante di queste istanze "server" fanno hai? Stanno parlando di 10k ... So che l'overhead è basso, ma l'idea è di minimizzare questo. Sto solo facendo la domanda ... è possibile? –

+0

Non penso che tu possa avere thread 10k :-) – alex2k8

+0

Sì, sarebbe necessario un pool di thread, ma il punto è che c'è un sovraccarico di prestazioni associato all'avvio di un nuovo thread e ad ogni thread è allocata anche una certa memoria per il suo stack ecc. Questo si aggiunge ed è indesiderabile. –

2

Mike,

Non è possibile annullare ReadFile sincrono. Ma puoi passare alle operazioni asincrone (sovrapposte). In questo modo, è possibile implementare un'architettura abbastanza scalabile.

algoritmo Possibile (solo un'idea):

  • Per ogni nuovo cliente ReadFile chiamata
  • WaitForMultipleObjects dove i manici sono overlapped.hEvent + tuoi eventi personalizzati
  • iterare segnalati eventi, e il calendario loro per l'esecuzione da thread da un pool di thread.

In questo modo è possibile avere solo pochi thread per ricevere connessioni e leggere dati, mentre l'elaborazione dati effettiva può essere eseguita dal pool di thread.

+0

Sì. Questa è la prossima fase del design. sfortunatamente ho ereditato la maggior parte di questo problema. L'IPC non è aperto a me, né le specifiche FastCGI. Ero un tiro lungo, ma pensavo che avrei chiesto nel caso qualcuno avesse una tecnica per rompere il blocco. –

5

dare uno sguardo su CancelSynchronousIo

Marks attesa sincrono I/O operazioni che vengono emessi dal thread specificato come annullata.

E CancelIo/CancelIoEx:

Per annullare tutte le richieste di I/O asincrono operazioni, utilizzare uno:

CancelIo - questa funzione viene annullato solo operazioni emessi dalla chiamando filo per l'handle del file specificato.

CancelIoEx: questa funzione annulla tutte le operazioni emesse dai thread per l'handle di file specificato.

+0

Oooh. Ho perso che ... minima supportata client \t Windows Vista minima supportata server di Windows Server 2008 \t Purtroppo questo è Windows Server 2003. Darn –

+1

Google per 'MSDN sincrone e asincrone di I/O' articolo. Sembra che l'unica opzione rimasta sia TerminateThread, ma questa sarebbe una cattiva idea (google per 'msdn TerminateThread può causare i seguenti problemi') – alex2k8

+0

Ulteriori informazioni qui: http://msdn.microsoft.com/en-us/library/ aa480216.aspx ("Supporto per l'annullamento I/O Win32 in Windows Vista"). –

11

Prova questa prima ReadFile:

BOOL WINAPI PeekNamedPipe(
    __in  HANDLE hNamedPipe, 
    __out_opt LPVOID lpBuffer, 
    __in  DWORD nBufferSize, 
    __out_opt LPDWORD lpBytesRead, 
    __out_opt LPDWORD lpTotalBytesAvail, 
    __out_opt LPDWORD lpBytesLeftThisMessage 
); 

if(TotalBytesAvail > 0) 
    ReadFile(....); 

-Av-

+0

Funziona come pubblicizzato, ma si presuppone che ci siano dati nella pipe da leggere. Il problema è che abbiamo bisogno di ReadFile() per bloccare UNTIL ci sono dati inviati. Quindi leggiamo i dati e torniamo allo stato di blocco di ReadFile(). Se non usiamo il blocco di ReadFile (0 allora avremmo bisogno di controllare costantemente la pipe (annullando lo scopo del blocco in primo luogo) –

+0

Great Stuff, questo funziona anche per pipe anonime –

0

Qual accadendo è il tubo del server in uscita viene lasciata aperta in attesa per la connessione, mentre il vostro cliente sta tentando di connettersi al server di entrata pipe (che non esiste più) ... Quello che devi fare è svuotare la tua pipe in uscita per tornare al tuo inbound.È possibile svuotare lato client leggendo il file (ricordarsi di eseguire il looping della connessione perché c'è una "stretta di mano" e non funzionerà mai la prima volta)

+0

Le persone hanno conosciuto la risposta a questo domanda per 8 anni compagno, perché rispondere ora? – Droopy

Problemi correlati