Chiamate di procedure asincrone
Una chiamata di routine asincrona (APC) è una funzione che viene eseguita in modo asincrono nel contesto di un determinato thread. Quando un APC viene accodato a un thread, il sistema genera un interrupt software. Alla successiva pianificazione del thread, eseguirà la funzione APC. Un APC generato dal sistema viene chiamato APC in modalità kernel . Un APC generato da un'applicazione viene chiamato APC in modalità utente . Un thread deve trovarsi in uno stato di avviso per eseguire un APC in modalità utente.
Ogni thread ha una propria coda APC. Un'applicazione accoda un APC a un thread chiamando la funzione QueueUserAPC. Il thread chiamante specifica l'indirizzo di una funzione APC nella chiamata a QueueUserAPC. L'accodamento di un APC è una richiesta per il thread per chiamare la funzione APC.
Quando un APC in modalità utente viene accodato, il thread a cui viene accodato non viene indirizzato per chiamare la funzione APC a meno che non si trova in uno stato di avviso. Un thread entra in uno stato di avviso quando chiama ilSleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsExo funzione WaitForSingleObjectEx. Se l'attesa viene soddisfatta prima che il servizio APC venga accodato, il thread non è più in uno stato di attesa avvisabile in modo che la funzione APC non venga eseguita. Tuttavia, il servizio APC è ancora in coda, quindi la funzione APC verrà eseguita quando il thread chiama un'altra funzione di attesa avvisabile.
Le ReadFileEx, SetWaitableTimer, SetWaitableTimerExe WriteFileEx vengono implementate usando un APC come meccanismo di callback delle notifiche di completamento.
Se si usa un pool di thread , si noti che le API non funzionano così come altri meccanismi di segnalazione perché il sistema controlla la durata dei thread del pool di thread, quindi è possibile che un thread venga terminato prima del recapito della notifica. Anziché usare un meccanismo di segnalazione basato su APC, ad esempio pfnCompletionRoutine parametro di SetWaitableTimer o SetWaitableTimerEx, usare un oggetto waitable, ad esempio un timer creato con CreateThreadpoolTimer. Per le operazioni di I/O, usare un oggetto di completamento I/O creato con CreateThreadpoolIo o un hEventbasato su structure OVERLAPPED in cui l'evento può essere passato alla funzione SetThreadpoolWait.
Internals di sincronizzazione
Quando viene eseguita una richiesta di I/O, viene allocata una struttura per rappresentare la richiesta. Questa struttura è denominata pacchetto di richiesta di I/O (IRP). Con l'I/O sincrono, il thread compila l'IRP, lo invia allo stack di dispositivi e attende il completamento dell'IRP nel kernel. Con l'I/O asincrono, il thread compila l'IRP e lo invia allo stack di dispositivi. Lo stack potrebbe completare immediatamente l'IRP oppure potrebbe restituire uno stato in sospeso che indica che la richiesta è in corso. In questo caso, l'IRP è ancora associato al thread, quindi verrà annullato se il thread termina o chiama una funzione, ad esempio CancelIo. Nel frattempo, il thread può continuare a eseguire altre attività mentre lo stack di dispositivi continua a elaborare l'IRP.
Esistono diversi modi in cui il sistema può indicare che l'IRP è stato completato:
- Aggiornare la struttura sovrapposta con il risultato dell'operazione in modo che il thread possa eseguire il polling per determinare se l'operazione è stata completata.
- Segnalare l'evento nella struttura sovrapposta in modo che un thread possa eseguire la sincronizzazione sull'evento e essere riattivato al termine dell'operazione.
- Accodare l'IRP all'APC in sospeso del thread in modo che il thread eseleva la routine APC quando entra in uno stato di attesa avvisabile e restituisca dall'operazione di attesa con uno stato che indica che ha eseguito una o più routine APC.
- Accodare l'IRP a una porta di completamento di I/O, in cui verrà eseguita dal thread successivo che attende la porta di completamento.
I thread che attendono una porta di completamento I/O non attendono uno stato di avviso. Pertanto, se questi thread rilasciano i runtime di integrazione impostati per il completamento come APC al thread, tali completamenti IPC non si verificheranno in modo tempestivo; si verificheranno solo se il thread preleva una richiesta dalla porta di completamento di I/O e quindi si verifica un'attesa avvisabile.
Argomenti correlati