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 haya completado la solicitud de E/S. Un subproceso que realiza E /S de archivo asincrónico envía una solicitud de E/S al kernel mediante una llamada 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 señale al subproceso que se completa 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.

E/S sincrónica y asincrónica

En situaciones en las que se espera que una solicitud de E/S tarde una gran cantidad de tiempo, como una actualización o 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 eficiencia 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 del 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 particulares de la aplicación. En otras palabras, normalmente hay varias maneras de resolver el problema.

Consideraciones de E/S sincrónicas y asincrónicas

Si se abre un archivo o dispositivo para E/S sincrónica (es decir, no se especifica FILE_FLAG_OVERLAPPED ), las llamadas subsiguientes a funciones como WriteFile pueden bloquear la ejecución del subproceso de llamada hasta que se produzca uno de los siguientes eventos:

  • 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 produjo 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 se termina u otro subproceso llama a la función TerminateThread mediante el identificador del subproceso bloqueado. (Esto generalmente se considera 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 objetos de sincronización de subprocesos adecuados, como puertos de finalización de E/S. Para obtener más información sobre 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 SUPERPUESTA en la llamada a ReadFile y WriteFile. Al realizar E/S sincrónica, esta estructura no es necesaria en las 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, vea https://support.microsoft.com/kb/156932.

 

Aunque CreateFile es la función más común que se va a usar 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 el socket o aceptar funciones.

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 las usarán.

Después de abrir el objeto de archivo para E/S asincrónica, se debe crear, inicializar y pasar correctamente a cada llamada a funciones como ReadFile y WriteFile. Tenga en cuenta lo siguiente al usar la estructura SUPERPUESTA en operaciones asincrónicas de lectura y escritura:

  • No desasigne ni modifique la estructura SUPERPUESTA 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 SUPERPUESTA 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 la función local se sale prematuramente, la estructura SUPERPUESTA 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 SUPERPUESTA ; Las funciones de espera se pueden usar para esperar a que se complete la operación de E/S esperando el identificador de eventos.

Como se indicó anteriormente, al trabajar con un identificador asincrónico, las aplicaciones deben usar cuidado al tomar decisiones sobre cuándo liberar recursos asociados a una operación de E/S especificada en ese identificador. Si el identificador se desasigna prematuramente, ReadFile o WriteFile puede informar incorrectamente de que la operación de E/S está completa. 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 porque TRUE y ERROR_SUCCESS indicar 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 WriteFile devuelve TRUE con ERROR_SUCCESS además de en la rutina de puerto de finalización de E/S, tendrá una condición de error de doble libre. En este ejemplo, la recomendación sería permitir que la rutina de puerto de finalización sea exclusivamente responsable de todas las operaciones de liberación de 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 SUPERPUESTA . Para obtener más información, vea 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 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 único archivo, debe esperar al identificador de eventos en la estructura SUPERPUESTA 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 completa la solicitud de E/S asincrónica.