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. |
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. |
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.
Seções relacionadas
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.