Sincronizzazione e output sovrapposti

È possibile eseguire operazioni di I/O sincrone o asincrone (dette anche sovrapposte) su file, named pipe e dispositivi di comunicazione seriale. Le funzioni WriteFile, ReadFile, DeviceIoControl, WaitCommEvent, ConnectNamedPipe e TransactNamedPipe possono essere eseguite in modo sincrono o asincrono. Le funzioni ReadFileEx e WriteFileEx possono essere eseguite solo in modo asincrono.

Quando una funzione viene eseguita in modo sincrono, non restituisce fino al completamento dell'operazione. Ciò significa che l'esecuzione del thread chiamante può essere bloccata per un periodo indefinito mentre attende il completamento di un'operazione che richiede molto tempo. Le funzioni chiamate per l'operazione sovrapposta possono restituire immediatamente, anche se l'operazione non è stata completata. Ciò consente l'esecuzione in background di un'operazione di I/O dispendiosa in termini di tempo, mentre il thread chiamante è libero di eseguire altre attività. Ad esempio, un singolo thread può eseguire operazioni di I/O simultanee su handle diversi o anche operazioni di lettura e scrittura simultanee sullo stesso handle.

Per sincronizzare l'esecuzione con il completamento dell'operazione sovrapposta, il thread chiamante usa la funzione GetOverlappedResult , la funzione GetOverlappedResultEx o una delle funzioni di attesa per determinare quando è stata completata l'operazione sovrapposta. È anche possibile utilizzare la macro HasOverlappedIoCompleted per eseguire il polling per il completamento.

Per annullare tutte le operazioni di I/O asincrone in sospeso, usare la funzione CancelIoEx e fornire una struttura OVERLAPPED che specifica la richiesta di annullamento. Usare la funzione CancelIo per annullare le operazioni di I/O asincrone in sospeso rilasciate dal thread chiamante per l'handle di file specificato.

Le operazioni sovrapposte richiedono un file, una named pipe o un dispositivo di comunicazione creato con il flag FILE_FLAG_OVERLAPPED . Quando un thread chiama una funzione (ad esempio la funzione ReadFile ) per eseguire un'operazione sovrapposta, il thread chiamante deve specificare un puntatore a una struttura OVERLAPPED . Se questo puntatore è NULL, il valore restituito dalla funzione potrebbe indicare erroneamente che l'operazione è stata completata. Tutti i membri della struttura OVERLAPPED devono essere inizializzati su zero, a meno che non venga usato un evento per segnalare il completamento di un'operazione di I/O. Se viene utilizzato un evento, il membro hEvent della struttura OVERLAPPED specifica un handle per l'oggetto evento allocato. Il sistema imposta lo stato dell'oggetto evento su non assegnato quando viene restituita una chiamata alla funzione di I/O prima del completamento dell'operazione. Il sistema imposta lo stato dell'oggetto evento su segnalato al termine dell'operazione. È necessario un evento solo se sono presenti più operazioni di I/O in sospeso contemporaneamente. Se non viene usato un evento, ogni operazione di I/O completata segnalerà il file, la named pipe o il dispositivo di comunicazione.

Quando viene chiamata una funzione per eseguire un'operazione sovrapposta, è possibile che l'operazione venga completata prima della restituzione della funzione. In questo caso, i risultati vengono gestiti come se l'operazione fosse stata eseguita in modo sincrono. Se l'operazione non è stata completata, tuttavia, il valore restituito della funzione è FALSE e la funzione GetLastError restituisce ERROR_IO_PENDING.

Un thread può gestire le operazioni sovrapposte tramite uno dei due metodi seguenti:

  • Usare la funzione GetOverlappedResult o GetOverlappedResultEx per attendere il completamento dell'operazione sovrapposta. Se viene usato GetOverlappedResultEx , il thread chiamante può specificare un timeout per l'operazione sovrapposta o eseguire un'attesa avvisabile.
  • Specificare un handle per l'oggetto evento di reimpostazione manuale della struttura OVERLAPPED in una delle funzioni di attesa e quindi, dopo la restituzione della funzione wait, chiamare GetOverlappedResult o GetOverlappedResultEx. La funzione restituisce i risultati dell'operazione sovrapposta completata e per le funzioni in cui tali informazioni sono appropriate, segnala il numero effettivo di byte trasferiti.

Quando si eseguono più operazioni sovrapposte simultanee su un singolo thread, il thread chiamante deve specificare una struttura OVERLAPPED per ogni operazione. Ogni struttura OVERLAPPED deve specificare un handle per un oggetto evento di reimpostazione manuale diverso. Per attendere il completamento di una delle operazioni sovrapposte, il thread specifica tutti gli handle di evento di reimpostazione manuale come criteri di attesa in una delle funzioni di attesa a più oggetti. Il valore restituito della funzione di attesa a più oggetti indica l'oggetto evento di reimpostazione manuale segnalato, in modo che il thread possa determinare quale operazione sovrapposta ha causato il completamento dell'operazione di attesa.

È più sicuro usare un oggetto evento separato per ogni operazione sovrapposta, anziché specificare alcun oggetto evento o riutilizzare lo stesso oggetto evento per più operazioni. Se nella struttura OVERLAPPED non viene specificato alcun oggetto evento, il sistema segnala lo stato del file, della named pipe o del dispositivo di comunicazione al termine dell'operazione sovrapposta. Pertanto, è possibile specificare questi handle come oggetti di sincronizzazione in una funzione di attesa, anche se l'uso per questo scopo può essere difficile da gestire perché, quando si eseguono operazioni sovrapposte simultanee sullo stesso file, sulla named pipe o sul dispositivo di comunicazione, non è possibile sapere quale operazione ha causato la segnalazione dello stato dell'oggetto.

Un thread non deve riutilizzare un evento presupponendo che l'evento venga segnalato solo dall'operazione sovrapposta del thread. Viene segnalato un evento sullo stesso thread dell'operazione sovrapposta completata. L'uso dello stesso evento su più thread può causare una race condition in cui l'evento viene segnalato correttamente per il thread la cui operazione viene completata prima e prematuramente per altri thread che usano tale evento. Al termine dell'operazione sovrapposta successiva, l'evento viene segnalato di nuovo per tutti i thread che usano tale evento e così via fino al completamento di tutte le operazioni sovrapposte.

Per esempi che illustrano l'uso di operazioni sovrapposte, routine di completamento e funzione GetOverlappedResult , vedere Using Pipes.

Windows Vista, Windows Server 2003 e Windows XP:

Prestare attenzione quando si riutilizzano strutture OVERLAPPED . Se le strutture OVERLAPPED vengono riutilizzate in più thread e GetOverlappedResult viene chiamato con il parametro bWait impostato su TRUE, il thread chiamante deve assicurarsi che l'evento associato venga segnalato prima di riutilizzare la struttura. A tale scopo, è possibile usare la funzione WaitForSingleObject dopo aver chiamato GetOverlappedResult per forzare l'attesa del thread fino al completamento dell'operazione. Si noti che l'oggetto evento deve essere un oggetto evento di reimpostazione manuale. Se viene utilizzato un oggetto evento autoreset, chiamando GetOverlappedResult con il parametro bWait impostato su TRUE , la funzione viene bloccata per un periodo illimitato. Questo comportamento è cambiato a partire da Windows 7 e Windows Server 2008 R2 per le applicazioni che specificano Windows 7 come sistema operativo supportato nel manifesto dell'applicazione. Per altre informazioni, vedere Manifesti dell'applicazione.

Concetti relativi alle I/O