Funzioni wait

Le funzioni di attesa consentono a un thread di bloccare la propria esecuzione. Le funzioni di attesa non restituiscono finché non sono stati soddisfatti i criteri specificati. Il tipo di funzione wait determina il set di criteri utilizzati. Quando viene chiamata una funzione wait, controlla se i criteri di attesa sono stati soddisfatti. Se i criteri non sono stati soddisfatti, il thread chiamante entra nello stato di attesa fino a quando non sono state soddisfatte le condizioni dei criteri di attesa o l'intervallo di timeout specificato scade.

Funzioni di attesa a oggetto singolo

Le funzioni SignalObjectAndWait, WaitForSingleObject e WaitForSingleObjectEx richiedono un handle per un oggetto di sincronizzazione. Queste funzioni restituiscono quando si verifica una delle operazioni seguenti:

  • L'oggetto specificato si trova nello stato segnalato.
  • Intervallo di timeout trascorso. L'intervallo di timeout può essere impostato su INFINITE per specificare che l'attesa non si verifica il timeout.

La funzione SignalObjectAndWait consente al thread chiamante di impostare in modo atomico lo stato di un oggetto su segnalato e attendere che lo stato di un altro oggetto venga impostato su segnalato.

Funzioni di attesa a più oggetti

Le funzioni WaitForMultipleObjects, WaitForMultipleObjectsEx, MsgWaitForMultipleObjects e MsgWaitForMultipleObjectsEx consentono al thread chiamante di specificare una matrice contenente uno o più handle di oggetti di sincronizzazione. Queste funzioni restituiscono quando si verifica una delle operazioni seguenti:

  • Lo stato di uno qualsiasi degli oggetti specificati è impostato su segnalato o gli stati di tutti gli oggetti sono stati impostati su segnalato. È possibile controllare se uno o tutti gli stati verranno usati nella chiamata di funzione.
  • Intervallo di timeout trascorso. L'intervallo di timeout può essere impostato su INFINITE per specificare che l'attesa non si verifica il timeout.

La funzione MsgWaitForMultipleObjects e MsgWaitForMultipleObjectsEx consentono di specificare oggetti evento di input nella matrice di handle oggetto. Questa operazione viene eseguita quando si specifica il tipo di input da attendere nella coda di input del thread. Ad esempio, un thread potrebbe usare MsgWaitForMultipleObjects per bloccare l'esecuzione fino a quando lo stato di un oggetto specificato non è stato impostato su segnalato e nella coda di input del thread è disponibile l'input del mouse. Il thread può usare la funzione GetMessage o PeekMessageA o PeekMessageW per recuperare l'input.

Quando si attende che gli stati di tutti gli oggetti vengano impostati su segnalato, queste funzioni a oggetti multipli non modificano gli stati degli oggetti specificati fino a quando non vengono impostati gli stati di tutti gli oggetti. Ad esempio, lo stato di un oggetto mutex può essere segnalato, ma il thread chiamante non ottiene la proprietà finché anche gli stati degli altri oggetti specificati nella matrice sono stati impostati su segnalato. Nel frattempo, un altro thread può ottenere la proprietà dell'oggetto mutex, impostandone lo stato su non firmato.

Quando si attende che lo stato di un singolo oggetto venga impostato su segnalato, queste funzioni a più oggetti controllano gli handle nella matrice in ordine a partire dall'indice 0, fino a quando non viene segnalato uno degli oggetti. Se vengono rilevati più oggetti, la funzione restituisce l'indice del primo handle nella matrice il cui oggetto è stato segnalato.

Funzioni di attesa avvisibili

Le funzioni MsgWaitForMultipleObjectsEx, SignalObjectAndWait, WaitForMultipleObjectsEx e WaitForSingleObjectEx differiscono dalle altre funzioni di attesa in quanto possono facoltativamente eseguire un'operazione di attesa di avviso. In un'operazione di attesa avvisabile, la funzione può restituire quando vengono soddisfatte le condizioni specificate, ma può anche restituire se la routine di completamento di I/O viene accodata o un APC per l'esecuzione dal thread in attesa. Per altre informazioni sulle operazioni di attesa di avviso e sulle routine di completamento di I/O, vedere Sincronizzazione e input e output sovrapposti. Per altre informazioni sulle API, vedere Chiamate di routine asincrone.

Funzioni di attesa registrate

La funzione RegisterWaitForSingleObject è diversa dalle altre funzioni di attesa in quanto l'operazione di attesa viene eseguita da un thread dal pool di thread. Quando vengono soddisfatte le condizioni specificate, la funzione di callback viene eseguita da un thread di lavoro dal pool di thread.

Per impostazione predefinita, un'operazione di attesa registrata è un'operazione di attesa multipla. Il sistema reimposta il timer ogni volta che l'evento viene segnalato (o scade l'intervallo di timeout) fino a quando non si chiama la funzione UnregisterWaitEx per annullare l'operazione. Per specificare che un'operazione di attesa deve essere eseguita una sola volta, impostare il parametro dwFlags di RegisterWaitForSingleObject su WT_EXECUTEONLYONCE.

Se il thread chiama le funzioni che usano LEC, impostare il parametro dwFlags di RegisterWaitForSingleObject su WT_EXECUTEINPERSISTENTTHREAD.

In attesa di un indirizzo

Un thread può usare la funzione WaitOnAddress per attendere che il valore di un indirizzo di destinazione cambi da un valore indesiderato a qualsiasi altro valore. Ciò consente ai thread di attendere che un valore venga modificato senza dover ruotare o gestire i problemi di sincronizzazione che possono verificarsi quando il thread acquisisce un valore indesiderato, ma il valore cambia prima che il thread possa attendere.

WaitOnAddress restituisce quando il codice che modifica il valore di destinazione segnala la modifica chiamando WakeByAddressSingle per riattivare un singolo thread in attesa o WakeByAddressAll per riattivare tutti i thread in attesa. Se viene specificato un intervallo di timeout con WaitOnAddress e nessun thread chiama una funzione di riattivazione, la funzione restituisce quando scade l'intervallo di timeout. Se non viene specificato alcun intervallo di timeout, il thread attende per un periodo illimitato.

Funzioni di attesa e intervalli di timeout

L'accuratezza dell'intervallo di timeout specificato dipende dalla risoluzione dell'orologio di sistema. L'orologio di sistema "ticks" a una frequenza costante. Se l'intervallo di timeout è minore della risoluzione dell'orologio di sistema, l'attesa potrebbe scadere in meno del periodo di tempo specificato. Se l'intervallo di timeout è maggiore di un tick ma minore di due, l'attesa può essere compresa tra uno e due tick e così via.

Per aumentare l'accuratezza dell'intervallo di timeout per le funzioni di attesa, chiamare la funzione timeGetDevCaps per determinare la risoluzione minima del timer supportata e la funzione timeBeginPeriod per impostare la risoluzione del timer sul valore minimo. Prestare attenzione quando si chiama timeBeginPeriod, poiché le chiamate frequenti possono influire in modo significativo sull'orologio di sistema, sull'utilizzo dell'alimentazione del sistema e sull'utilità di pianificazione. Se si chiama timeBeginPeriod, chiamarlo una volta all'inizio dell'applicazione e assicurarsi di chiamare la funzione timeEndPeriod alla fine dell'applicazione.

Funzioni di attesa e oggetti di sincronizzazione

Le funzioni di attesa possono modificare gli stati di alcuni tipi di oggetti di sincronizzazione. La modifica si verifica solo per l'oggetto o gli oggetti il cui stato segnalato ha causato la restituzione della funzione. Le funzioni di attesa possono modificare gli stati degli oggetti di sincronizzazione come indicato di seguito:

  • Il conteggio di un oggetto semaforo diminuisce di uno e lo stato del semaforo è impostato su non assegnato se il conteggio è zero.
  • Gli stati di mutex, evento di reimpostazione automatica e oggetti change-notification sono impostati su non firmati.
  • Lo stato di un timer di sincronizzazione è impostato su non firmato.
  • Gli stati degli eventi di reimpostazione manuale, timer di reimpostazione manuale, processo, thread e oggetti di input della console non sono interessati da una funzione di attesa.

Funzioni di attesa e creazione di Windows

È necessario prestare attenzione quando si usano le funzioni di attesa e il codice che crea direttamente o indirettamente le finestre. Se un thread crea finestre, deve elaborare i messaggi. Le trasmissioni dei messaggi vengono inviate a tutte le finestre del sistema. Se si dispone di un thread che usa una funzione di attesa senza intervallo di timeout, il sistema eseguirà il deadlock. Due esempi di codice che creano indirettamente finestre sono DDE e la funzione CoInitialize . Pertanto, se si dispone di un thread che crea finestre, usare MsgWaitForMultipleObjects o MsgWaitForMultipleObjectsEx, anziché le altre funzioni di attesa.