Estruturas de dados de sincronização

O Runtime de Simultaneidade fornece várias estruturas de dados que permitem sincronizar o acesso a dados compartilhados de vários threads. Essas estruturas de dados são úteis quando você tem dados compartilhados que são modificados com pouca frequência. Um objeto de sincronização, por exemplo, uma seção crítica, faz com que outros threads aguardem até que o recurso compartilhado esteja disponível. Portanto, se você usar esse objeto para sincronizar o acesso aos dados usados com frequência, poderá perder a escalabilidade em seu aplicativo. A PPL (Biblioteca de padrões paralelos) fornece a classe concurrency::combinable, que permite compartilhar um recurso entre vários threads ou tarefas sem a necessidade de sincronização. Para mais informações sobre a classe combinable, confira Contêineres e objetos paralelos.

Seções

Este tópico descreve os seguintes tipos de bloco de mensagem assíncrona em detalhes:

critical_section

A classe concurrency::critical_section representa um objeto cooperativo de exclusão mútua que permite outras tarefas em vez de se impedi-las. Seções críticas são úteis quando vários threads exigem acesso exclusivo de leitura e gravação a dados compartilhados.

A classe critical_section é não reentrante. O método concurrency::critical_section::lock gerará uma exceção do tipo concurrency::improper_lock se for chamado pelo thread que já possui o bloqueio.

Métodos e Recursos

A tabela a seguir mostra os métodos importantes definidos pela classe critical_section.

Método Descrição
lock Adquire a seção crítica. O contexto de chamada bloqueia até ele adquirir o bloqueio.
try_lock Tenta adquirir a seção crítica, mas não bloqueia.
unlock Libera a seção crítica.

[Parte superior]

reader_writer_lock

A classe concurrency::reader_writer_lock fornece operações de leitura/gravação thread-safe para dados compartilhados. Use bloqueios de leitor/gravador quando vários threads exigem acesso de leitura simultâneo a um recurso compartilhado, mas raramente gravam nesse recurso compartilhado. Essa classe fornece apenas um acesso de gravação de thread a um objeto a qualquer momento.

A classe reader_writer_lock pode ter um desempenho melhor do que a classe critical_section porque um objeto critical_section adquire acesso exclusivo a um recurso compartilhado, o que impede o acesso de leitura simultâneo.

Assim como a classe critical_section, a classe reader_writer_lock representa um objeto cooperativo de exclusão mútua que permite outras tarefas em vez de se impedi-las.

Quando um thread que deve gravar em um recurso compartilhado adquire um bloqueio de leitor/gravador, outros threads que também devem acessar o recurso são bloqueados até que o gravador libere o bloqueio. A classe reader_writer_lock é um exemplo de um bloqueio de preferência de gravação, que é um bloqueio que desbloqueia os gravadores em espera antes de desbloquear leitores em espera.

Assim como a classe critical_section, a classe reader_writer_lock é não reentrante. Os métodos concurrency::reader_writer_lock::lock e concurrency::reader_writer_lock::lock_read gerarão uma exceção do tipo improper_lock se forem chamados por um thread que já possui o bloqueio.

Observação

Como a classe reader_writer_lock é não reentrante, você não pode atualizar um bloqueio somente leitura para um bloqueio de leitor/gravador ou fazer downgrade de um bloqueio de leitor/gravador para um bloqueio somente leitura. Executar qualquer uma dessas operações produz um comportamento não especificado.

Métodos e Recursos

A tabela a seguir mostra os métodos importantes definidos pela classe reader_writer_lock.

Método Descrição
lock Adquire acesso de leitura/gravação ao bloqueio.
try_lock Tenta adquirir acesso de leitura/gravação ao bloqueio, mas não bloqueia.
lock_read Adquire acesso somente leitura ao bloqueio.
try_lock_read Tenta adquirir acesso somente leitura ao bloqueio, mas não bloqueia.
unlock Libera o bloqueio.

[Parte superior]

scoped_lock e scoped_lock_read

As classes critical_section e reader_writer_lock fornecem classes auxiliares aninhadas que simplificam a maneira como você trabalha com objetos de exclusão mútua. Essas classes auxiliares são conhecidas como bloqueios com escopo.

A classe critical_section contém a classe concurrency::critical_section::scoped_lock. O construtor adquire acesso ao objeto fornecido critical_section; o destruidor libera o acesso a esse objeto. A classe reader_writer_lock contém a classe concurrency::reader_writer_lock::scoped_lock, que é semelhante a critical_section::scoped_lock, exceto que gerencia o acesso de gravação ao objeto fornecido reader_writer_lock. A classe reader_writer_lock também contém a classe concurrency::reader_writer_lock::scoped_lock_read. Essa classe gerencia o acesso de leitura ao objeto fornecido reader_writer_lock.

Os bloqueios com escopo fornecem vários benefícios quando você está trabalhando com objetos critical_section e reader_writer_lock manualmente. Normalmente, você aloca um bloqueio com escopo na pilha. Um bloqueio com escopo libera o acesso ao objeto de exclusão mútua automaticamente quando ele é destruído; portanto, você não desbloqueia manualmente o objeto subjacente. Isso é útil quando uma função contém várias instruções return. Os bloqueios com escopo também podem ajudá-lo a escrever código seguro de exceção. Quando uma instrução throw faz com que a pilha se desfaça, o destruidor de qualquer bloqueio com escopo ativo é chamado e, portanto, o objeto de exclusão mútua é sempre liberado corretamente.

Observação

Quando você usa as classes critical_section::scoped_lock, reader_writer_lock::scoped_lock e reader_writer_lock::scoped_lock_read, não libere manualmente o acesso ao objeto de exclusão mútua subjacente. Isso pode colocar o runtime em um estado inválido.

event

A classe concurrency::event representa um objeto de sincronização cujo estado pode ser sinalizado ou não sinalizado. Ao contrário dos objetos de sincronização, como seções críticas, cuja finalidade é proteger o acesso a dados compartilhados, os eventos sincronizam o fluxo de execução.

A classe event é útil quando uma tarefa conclui o trabalho para outra tarefa. Por exemplo, uma tarefa pode sinalizar outra tarefa de que tem dados de leitura de uma conexão de rede ou de um arquivo.

Métodos e Recursos

A tabela a seguir mostra vários dos métodos importantes definidos pela classe event.

Método Descrição
wait Aguarda que o evento seja sinalizado.
set Define o evento como o estado sinalizado.
reset Define o evento como o estado não sinalizado.
wait_for_multiple Aguarda que vários eventos sejam sinalizados.

Exemplo

Para obter um exemplo que mostra como usar a classe event, consulte Comparando estruturas de dados com a API do Windows.

[Parte superior]

Comparando estruturas de dados de sincronização com a API do Windows
Compara o comportamento das estruturas de dados de sincronização com as fornecidas pela API do Windows.

Runtime de Simultaneidade
Descreve o Runtime de Simultaneidade, que simplifica a programação paralela e contém links para tópicos relacionados.