2009-02-27 9 views
21

Para simplificar, se trata de una situación en la que un servidor NamedPipe se espera el cliente NamedPipe a escribir a la tubería (usando WriteFile())Breaking ReadFile() bloqueo - canalización con nombre (API de Windows)

La API de Windows que se bloquea es ReadFile()

el servidor ha creado la tubería síncrona (sin superpuesto e/S) con el bloqueo activado

el cliente se ha conectado, y ahora el servidor está a la espera de algunos datos.

En el flujo normal de cosas, el cliente envía algunos datos y el servidor los procesa y luego regresa a ReadFile() para esperar el siguiente fragmento de datos.

Mientras tanto ocurre un evento (por ejemplo, la entrada del usuario) y el SERVIDOR NamedPipe ahora debe ejecutar algún otro código, lo que no puede hacer mientras ReadFile() está bloqueando.

En este punto debo mencionar que el cliente de NamedPipe no es mi aplicación, por lo que no tengo control sobre ella. No puedo enviar unos bytes para desbloquear el servidor. Simplemente se sentará allí y no enviará datos. Como no tengo control de la implementación del Cliente, no puedo cambiar nada en ese extremo.

Una solución sería crear un hilo separado en el que se realicen todas las operaciones de ReadFile(). De esa forma, cuando ocurre el evento, puedo procesar el código. El problema con eso, es que el evento también requiere un hilo separado, por lo que ahora tengo dos hilos adicionales para cada instancia de este servidor. Como esto necesita ser escalable, esto no es deseable.

De otro hilo que he intentado llamar

DisconnectNamedPipe() 

y

CloseHandle() 

que ambos no volverán (hasta que el cliente escribe a la tubería.)

No me puedo conectar a la misma tubería y escriba algunos bytes porque:

"Todas las instancias de un nombre pipe comparte el mismo nombre de pipe, pero cada instancia tiene sus propios búferes y manejadores, y proporciona un conducto separado para la comunicación cliente/servidor ".

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

Necesito una manera de fingir a cabo, lo que la pregunta dólar $ 64k es:

¿Cómo puedo romper el bloqueo de ReadFile()?

Respuesta

1

El problema con esto, es que el evento también requiere un hilo separado, por lo que ahora tienen dos hilos adicionales para cada instancia de este servidor. Dado que esto necesita ser escalable, este es indeseable.

Nunca en mi carrera he encontrado que "más hilos" == "menos escalable". ¿Cuántas de estas instancias de "servidor" tiene?

Normalmente, una operación debe realizarse en una secuencia separada si esa operación se va a bloquear y el sistema debe responder mientras la operación está bloqueada.

+0

¿Cuántas de estas instancias de "servidor" ¿tienes? Están hablando de hasta 10k ... Sé que la sobrecarga es baja, pero la idea es minimizar esto. Solo estoy haciendo la pregunta ... ¿es posible? –

+0

No creo que pueda tener hilos de 10k :-) – alex2k8

+0

Sí, eso requeriría un grupo de subprocesos, pero el punto es que hay una sobrecarga de rendimiento asociada al inicio de un nuevo subproceso, y cada subproceso también tiene asignada memoria para su pila etc. Esto se suma y es indeseable. –

2

Mike,

No puede cancelar el archivo ReadFile sincrónico. Pero puede cambiar a operaciones asincrónicas (superpuestas). Al hacer esto, puede implementar una arquitectura bastante escalable.

algoritmo Posible (sólo una idea):

  • Para cada nuevo ReadFile llamada del cliente
  • WaitForMultipleObjects donde las asas son overlapped.hEvent + sus eventos personalizados
  • iterar sobre señalizan eventos, y el horario para su ejecución por subprocesos desde un grupo de subprocesos.

De esta manera puede tener solo unos pocos hilos para recibir conexiones y leer datos, mientras que el procesamiento de datos real puede hacerlo el grupo de hilos.

+0

Sí. Esa es la próxima etapa del diseño. desafortunadamente heredé la mayor parte de este problema. El IPC no está abierto para mí, ni lo es la especificación FastCGI. Era una posibilidad remota, pero pensé que podría preguntar en caso de que alguien tuviera una técnica para romper el bloqueo. –

5

echar un vistazo en CancelSynchronousIo

Marcas espera de E/S síncrona operaciones que son emitidos por el subproceso especificado como cancelada.

Y CancelIo/CancelIoEx:

Para cancelar todos a la espera de E/S asíncrona operaciones, utilice uno:

CancelIo - esta función sólo cancela operaciones emitidas por el hilo pidiendo el manejador de archivo especificado.

CancelIoEx - esta función cancela todas las operaciones emitidas por los hilos para el identificador de archivo especificado.

+0

Oooh. Echaba de menos que ... mínimo soportado cliente \t Windows Vista mínimo soportado servidor de Windows Server 2008 \t Desafortunadamente esto es Windows Server 2003. Darn –

+1

Google para 'MSDN síncrona y asíncrona de E/S' artículo. Parece que la única opción que queda es TerminateThread, pero esto sería una mala idea (google para 'msdn TerminateThread puede provocar los siguientes problemas') – alex2k8

+0

Más información aquí: http://msdn.microsoft.com/en-us/library/ aa480216.aspx ("Compatibilidad de cancelación de E/S de Win32 en Windows Vista"). –

11

antes de probar este 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

Esto funciona como se anuncia, pero supone que hay datos en el tubo para leer. El problema es que necesitamos ReadFile() para bloquear HASTA que haya datos enviados. Luego leemos los datos y volvemos al estado de bloqueo de ReadFile(). Si no utilizamos el bloqueo de ReadFile (0, entonces tendríamos que verificar constantemente el conducto (en primer lugar, se debe evitar el bloqueo) –

+0

Great Stuff, esto también funciona para tuberías anónimas –

0

Lo que pasa es la tubería de salida del servidor de espera se deja abierta para la conexión, mientras que su cliente está intentando conectar con el servidor de entrada tubería (que ya no existe) ... Lo que debe hacer es purgar su tubería de salida con el fin de regresar a su entrada.Puede limpiar el lado del cliente leyendo el archivo (recuerde hacer un bucle en el establecimiento de conexión porque hay un "saludo de mano" y nunca funcionará la primera vez)

+0

La gente ha sabido la respuesta a esto pregunta durante 8 años, compañero, ¿por qué responder ahora? – Droopy

Cuestiones relacionadas