E/S sincrónica y asincrónica
Consulte también Aplicaciones de ejemplo relacionadas con E/S.
Hay dos tipos de sincronización de entrada/salida (E/S): E/S sincrónica y E/S asincrónica. La E/S asincrónica también se conoce como E/S superpuesta.
En la E/S de archivo sincrónica, un subproceso inicia una operación de E/S y entra inmediatamente en un estado de espera hasta que se completa la solicitud de E/S. Un subproceso que realiza la E/S de archivo asincrónica envía una solicitud de E/S al kernel llamando a una función adecuada. Si el kernel acepta la solicitud, el subproceso que realiza la llamada continúa procesando otro trabajo hasta que el kernel indique al subproceso que se ha completado la operación de E/S. A continuación, interrumpe su trabajo actual y procesa los datos de la operación de E/S según sea necesario.
Los dos tipos de sincronización se muestran en la ilustración siguiente.
En situaciones en las que se espera que una solicitud de E/S va a tardar mucho, como una actualización o una copia de seguridad de una base de datos grande o un vínculo de comunicaciones lentas, la E/S asincrónica suele ser una buena manera de optimizar la eficacia del procesamiento. Sin embargo, para las operaciones de E/S relativamente rápidas, la sobrecarga de procesar las solicitudes de E/S del kernel y las señales de kernel pueden hacer que la E/S asincrónica sea menos beneficiosa, especialmente si es necesario realizar muchas operaciones de E/S rápidas. En este caso, la E/S sincrónica sería mejor. Los mecanismos y los detalles de implementación de cómo realizar estas tareas varían en función del tipo de identificador de dispositivo que se usa y de las necesidades específicas de la aplicación. En otras palabras, normalmente hay varias maneras de resolver el problema.
Consideraciones sobre la E/S sincrónica y asincrónica
Si se abre un archivo o dispositivo para E/S sincrónica (es decir, no se especifica FILE_FLAG_OVERLAPPED), las llamadas posteriores a funciones como WriteFile pueden bloquear la ejecución del subproceso de llamada hasta que se produzca uno de los eventos siguientes:
- La operación de E/S se completa (en este ejemplo, una escritura de datos).
- Error de E/S. (Por ejemplo, la canalización se cierra desde el otro extremo).
- Se ha producido un error en la propia llamada (por ejemplo, uno o varios parámetros no son válidos).
- Otro subproceso del proceso llama a la función CancelSynchronousIo mediante el identificador de subproceso bloqueado, que finaliza la E/S de ese subproceso y produce un error en la operación de E/S.
- El sistema termina el subproceso bloqueado; por ejemplo, el propio proceso finaliza u otro subproceso llama a la función TerminateThread mediante el identificador del subproceso bloqueado. (Esto suele considerarse un último recurso y no un buen diseño de aplicaciones).
En algunos casos, este retraso puede ser inaceptable para el diseño y el propósito de la aplicación, por lo que los diseñadores de aplicaciones deben considerar el uso de E/S asincrónica con los objetos de sincronización de subprocesos adecuados, como los puertos de finalización de E/S. Para obtener más información acerca de la sincronización de subprocesos, consulte Acerca de la sincronización.
Un proceso abre un archivo para la E/S asincrónica en su llamada a CreateFile especificando la marca FILE_FLAG_OVERLAPPED en el parámetro dwFlagsAndAttributes. Si no se especifica FILE_FLAG_OVERLAPPED, el archivo se abre para E/S sincrónica. Cuando el archivo se ha abierto para E/S asincrónica, se pasa un puntero a una estructura OVERLAPPED en la llamada a ReadFile y WriteFile. Al realizar la E/S sincrónica, esta estructura no es necesaria en llamadas a ReadFile y WriteFile.
Nota:
Si se abre un archivo o dispositivo para E/S asincrónica, las llamadas posteriores a funciones como WriteFile mediante ese identificador suelen devolverse inmediatamente, pero también pueden comportarse de forma sincrónica con respecto a la ejecución bloqueada. Para obtener más información, consulte La E/S de disco asincrónica aparece como sincrónica en Windows.
Aunque CreateFile es la función más común que se usa para abrir archivos, volúmenes de disco, canalizaciones anónimas y otros dispositivos similares, las operaciones de E/S también se pueden realizar mediante una difusión de tipos de identificador de otros objetos del sistema, como un socket creado por las funciones socket o aceptar.
Los identificadores de los objetos de directorio se obtienen llamando a la función CreateFile con el atributo FILE_FLAG_BACKUP_SEMANTICS. Los identificadores de directorio casi nunca se usan: las aplicaciones de copia de seguridad son una de las pocas aplicaciones que normalmente los usan.
Después de abrir el objeto de archivo para la E/S asincrónica, se debe crear, inicializar y pasar correctamente una estructura OVERLAPPED a cada llamada a funciones como ReadFile y WriteFile. Tenga en cuenta lo siguiente al usar la estructura OVERLAPPED en operaciones asincrónicas de lectura y escritura:
- No desasigne ni modifique la estructura OVERLAPPED o el búfer de datos hasta que se hayan completado todas las operaciones de E/S asincrónicas en el objeto de archivo.
- Si declara el puntero a la estructura OVERLAPPED como una variable local, no salga de la función local hasta que se hayan completado todas las operaciones de E/S asincrónicas en el objeto de archivo. Si se sale prematuramente de la función local, la estructura OVERLAPPED saldrá del ámbito y no podrá acceder a las funciones ReadFile o WriteFile que encuentre fuera de esa función.
También puede crear un evento y colocar el identificador en la estructura OVERLAPPED; las funciones de espera se pueden usar para esperar a que se complete la operación de E/S esperando al identificador de eventos.
Como se indicó anteriormente, al trabajar con un identificador asincrónico, las aplicaciones deben usar cuidado al realizar determinaciones sobre cuándo liberar recursos asociados a una operación de E/S especificada en ese identificador. Si el identificador se desasigna prematuramente, ReadFile or WriteFile puede notificar incorrectamente que se ha completado la operación de E/S. Además, la función WriteFile a veces devolverá TRUE con un valor GetLastError de ERROR_SUCCESS, aunque esté usando un identificador asincrónico (que también puede devolver FALSE con ERROR_IO_PENDING). Los programadores acostumbrados al diseño de E/S sincrónica normalmente liberarán recursos de búfer de datos en este momento, ya que TRUE y ERROR_SUCCESS indican que la operación está completa. Sin embargo, si los puertos de finalización de E/S se usan con este identificador asincrónico, también se enviará un paquete de finalización aunque la operación de E/S se complete inmediatamente. En otras palabras, si la aplicación libera recursos después de que WriteFile devuelva TRUE con ERROR_SUCCESS además de en la rutina de puerto de finalización de E/S, tendrá una condición de error doblemente libre. En este ejemplo, la recomendación sería permitir que la rutina de puerto de finalización sea la único responsable de todas las operaciones de liberar dichos recursos.
El sistema no mantiene el puntero de archivo en identificadores asincrónicos a archivos y dispositivos que admiten punteros de archivo (es decir, buscar dispositivos), por lo que la posición del archivo debe pasarse a las funciones de lectura y escritura en los miembros de datos de desplazamiento relacionados de la estructura OVERLAPPED. Para obtener más información, consulte WriteFile y ReadFile.
El sistema mantiene la posición del puntero de archivo para un identificador sincrónico a medida que los datos se leen o escriben y también se pueden actualizar mediante la función SetFilePointer o SetFilePointerEx.
Una aplicación también puede esperar en el identificador de archivo para sincronizar la finalización de una operación de E/S, pero hacerlo requiere extrema precaución. Cada vez que se inicia una operación de E/S, el sistema operativo establece el identificador de archivo en el estado no asignado. Cada vez que se completa una operación de E/S, el sistema operativo establece el identificador de archivo en el estado no señalado. Por lo tanto, si una aplicación inicia dos operaciones de E/S y espera en el identificador de archivo, no hay ninguna manera de determinar qué operación finaliza cuando el identificador se establece en el estado señalado. Si una aplicación debe realizar varias operaciones de E/S asincrónicas en un solo archivo, debe esperar al identificador de eventos en la estructura OVERLAPPED específica para cada operación de E/S, en lugar de en el identificador de archivo común.
Para cancelar todas las operaciones de E/S asincrónicas pendientes, use:
- CancelIo: esta función solo cancela las operaciones emitidas por el subproceso de llamada para el identificador de archivo especificado.
- CancelIoEx: esta función cancela todas las operaciones emitidas por los subprocesos para el identificador de archivo especificado.
Use CancelSynchronousIo para cancelar las operaciones de E/S sincrónicas pendientes.
Las funciones ReadFileEx y WriteFileEx permiten a una aplicación especificar una rutina para ejecutarse (consulte FileIOCompletionRoutine) cuando se complete la solicitud de E/S asincrónica.