Strutture di dati di sincronizzazione
Il runtime di concorrenza fornisce diverse strutture dei dati che consentono di sincronizzare l'accesso ai dati condivisi da più thread. Queste strutture dei dati sono utili in presenza di dati condivisi che vengono modificati raramente. Un oggetto di sincronizzazione, ad esempio una sezione critica, impone agli altri thread di attendere finché la risorsa condivisa non è disponibile. Pertanto, se si utilizza tale oggetto per sincronizzare l'accesso ai dati utilizzati di frequente, è possibile perdere scalabilità nell'applicazione. Nella libreria PPL (Parallel Patterns Library) è disponibile la classe Concurrency::combinable, che consente di condividere una risorsa tra diversi thread o attività senza la necessità di sincronizzazione.. Per ulteriori informazioni sulla classe combinable, vedere Contenitori e oggetti paralleli.
Sezioni
In questo argomento vengono descritti in dettaglio i tipi di blocco dei messaggi asincroni seguenti:
critical_section
reader_writer_lock
scoped_lock e scoped_lock_read
event
critical_section
La classe Concurrency::critical_section rappresenta un oggetto cooperativo a esclusione reciproca che cede il controllo ad altre attività anziché avere la precedenza su di esse. Le sezioni critiche sono utili quando più thread richiedono l'accesso esclusivo in lettura e scrittura ai dati condivisi.
La classe critical_section non è rientrante. Il metodo Concurrency::critical_section::lock genera un'eccezione di tipo Concurrency::improper_lock se viene chiamato dal thread già proprietario del blocco.
Metodi e funzionalità
Nella tabella seguente vengono illustrati i metodi principali definiti dalla classe critical_section.
Metodo |
Descrizione |
---|---|
Acquisisce la sezione critica. Il contesto di chiamata viene bloccato finché non viene acquisito il blocco. |
|
Tenta di acquisire la sezione critica, senza bloccarsi. |
|
Rilascia la sezione critica. |
[vai all'inizio]
reader_writer_lock
La classe Concurrency::reader_writer_lock fornisce le operazioni di lettura/scrittura thread-safe nei dati condivisi. Utilizzare i blocchi reader/writer quando più thread richiedono l'accesso in lettura simultaneo a una risorsa condivisa ma raramente scrivono nella risorsa condivisa. Questa classe concede a un oggetto sempre un solo accesso in scrittura al thread.
Le prestazioni della classe reader_writer_lock risultano migliori della classe critical_section poiché un oggetto critical_section acquisisce l'accesso esclusivo a una risorsa condivisa impedendo l'accesso in lettura simultaneo.
Analogamente alla classe critical_section, la classe reader_writer_lock rappresenta un oggetto cooperativo a esclusione reciproca che viene passato ad altre attività anziché annullarle.
Quando un thread che deve scrivere in una risorsa condivisa acquisisce un blocco reader/writer, gli altri thread che devono accedere alla risorsa vengono bloccati finché il writer non rilascia il blocco. La classe reader_writer_lock è un esempio di blocco con preferenza di scrittura, ovvero un blocco che sblocca i writer in attesa prima di sbloccare i reader in attesa.
Analogamente alla critical_section, la classe reader_writer_lock non è rientrante. I metodi Concurrency::reader_writer_lock::lock e Concurrency::reader_writer_lock::lock_read generano un'eccezione di tipo improper_lock se vengono chiamati da un thread già proprietario del blocco.
Nota
Poiché la classe reader_writer_lock non è rientrante, non è possibile aggiornare un blocco di sola lettura a un blocco di lettura/scrittura o declassare un blocco di lettura/scrittura a un blocco di sola lettura. L'esecuzione di entrambe queste operazioni produce un comportamento non specificato.
Metodi e funzionalità
Nella tabella seguente vengono illustrati i metodi principali definiti dalla classe reader_writer_lock.
Metodo |
Descrizione |
---|---|
Acquisisce l'accesso in lettura/scrittura al blocco. |
|
Tenta di acquisire l'accesso in lettura/scrittura al blocco, senza bloccarsi. |
|
Acquisisce l'accesso in sola lettura al blocco. |
|
Tenta di acquisire l'accesso in sola lettura al blocco, senza bloccarsi. |
|
Rilascia il blocco. |
[vai all'inizio]
scoped_lock e scoped_lock_read
Le classi critical_section e reader_writer_lock forniscono classi di supporto annidate che semplificano il modo di utilizzare gli oggetti a esclusione reciproca. Queste classi di supporto sono note come blocchi con ambito.
La classe critical_section include la classe Concurrency::critical_section::scoped_lock. Il costruttore acquisisce l'accesso all'oggetto critical_section fornito, mentre il distruttore rilascia l'accesso a tale oggetto. La classe reader_writer_lock include la classe Concurrency::reader_writer_lock::scoped_lock, che è simile a critical_section::scoped_lock, con l'unica differenza che gestisce l'accesso in scrittura all'oggetto reader_writer_lock fornito. La classe reader_writer_lock include inoltre la classe Concurrency::reader_writer_lock::scoped_lock_read. Questa classe gestisce l'accesso in lettura all'oggetto reader_writer_lock fornito.
I blocchi con ambito forniscono diversi vantaggi quando si utilizzano gli oggetti critical_section e reader_writer_lock manualmente. In genere, un blocco con ambito viene allocato nello stack. Un blocco con ambito rilascia automaticamente l'accesso al relativo oggetto a esclusione reciproca quando viene eliminato; pertanto, l'oggetto sottostante non viene manualmente sbloccato. Ciò si rivela utile quando una funzione contiene più istruzioni return. I blocchi con ambito possono inoltre consentire di scrivere il codice indipendentemente dalle eccezioni. Quando un'istruzione throw determina la rimozione dello stack, viene chiamato il distruttore di un blocco con ambito attivo e pertanto l'oggetto a esclusione reciproca viene sempre rilasciato correttamente.
Nota
Quando si utilizzano le classi critical_section::scoped_lock, reader_writer_lock::scoped_lock e reader_writer_lock::scoped_lock_read, non rilasciare manualmente l'accesso all'oggetto a esclusione reciproca sottostante, poiché il runtime può restituire uno stato non valido.
event
La classe Concurrency::event rappresenta un oggetto di sincronizzazione il cui stato può essere segnalato o non segnalato. A differenza degli oggetti di sincronizzazione, come le sezioni critiche, il cui scopo è proteggere l'accesso ai dati condivisi, gli eventi sincronizzano il flusso di esecuzione.
La classe event è utile quando un'attività ha completato il lavoro di un'altra attività. Ad esempio, un'attività potrebbe segnalare a un'altra attività di aver letto i dati da una connessione di rete o da un file.
Metodi e funzionalità
Nella tabella seguente vengono illustrati diversi metodi principali definiti dalla classe event.
Metodo |
Descrizione |
---|---|
Attende che l'evento venga segnalato. |
|
Imposta l'evento sullo stato segnalato. |
|
Imposta l'evento sullo stato non segnalato. |
|
Attende che più eventi vengano segnalati. |
Esempio
Per un esempio che illustra come utilizzare la classe event, vedere Confronto delle strutture di dati di sincronizzazione con l'API Windows.
[vai all'inizio]
Sezioni correlate
Confronto delle strutture di dati di sincronizzazione con l'API Windows
Viene confrontato il comportamento delle strutture dei dati di sincronizzazione con quelle fornite dall'API Windows.Runtime di concorrenza
Viene descritto il runtime di concorrenza che semplifica la programmazione parallela e vengono forniti i collegamenti ad argomenti correlati.