Condividi tramite


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

lock

Acquisisce la sezione critica. Il contesto di chiamata viene bloccato finché non viene acquisito il blocco.

try_lock

Tenta di acquisire la sezione critica, senza bloccarsi.

unlock

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

lock

Acquisisce l'accesso in lettura/scrittura al blocco.

try_lock

Tenta di acquisire l'accesso in lettura/scrittura al blocco, senza bloccarsi.

lock_read

Acquisisce l'accesso in sola lettura al blocco.

try_lock_read

Tenta di acquisire l'accesso in sola lettura al blocco, senza bloccarsi.

unlock

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

wait

Attende che l'evento venga segnalato.

set

Imposta l'evento sullo stato segnalato.

reset

Imposta l'evento sullo stato non segnalato.

wait_for_multiple

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