Contêineres e objetos em paralelo
A biblioteca (PPL) de padrões de paralela inclui vários contêineres e objetos que fornecem acesso isento a seus elementos.
Um contêiner simultânea fornece acesso simultaneidade- seguro para operações as mais importantes. A funcionalidade desses contêineres se assemelha a aquelas que são fornecidas pela biblioteca padrão (STL) do modelo. Por exemplo, a classe de concurrency::concurrent_vector é semelhante à classe de std::vector , exceto que a classe de concurrent_vector permite anexar os elementos em paralelo. Use contêineres simultâneas enquanto você tiver código paralelo que requer tanto o acesso de leitura e gravação para o mesmo contêiner.
Um objeto simultâneo é compartilhado simultaneamente entre os componentes. Um processo que calcula o estado de um objeto simultânea em paralelo gerencia o mesmo resultado que outro processo que calcula o mesmo estado em série. A classe de concurrency::combinable é um exemplo de um tipo de objeto simultâneo. A classe de combinable permite executar computações em paralelo, e combina-a nas computações em um resultado final. Use objetos simultâneos quando você usaria de outra forma um mecanismo de sincronização, por exemplo, um mutex, para sincronizar o acesso a uma variável ou em um recurso compartilhado.
Seções
Este tópico descreve os seguintes objetos contêiner e paralelos em detalhes.
Contêiner simultâneas:
classe de concurrent_vector
Diferenças entre o concurrent_vector e o vetor
Operações Simultaneidade-seguras
Segurança de exceção
classe de concurrent_queue
Diferenças entre o concurrent_queue e a fila
Operações Simultaneidade-seguras
Suporte de iterador
classe de concurrent_unordered_map
Diferenças entre o concurrent_unordered_map e o unordered_map
Operações Simultaneidade-seguras
classe de concurrent_unordered_multimap
classe de concurrent_unordered_set
classe de concurrent_unordered_multiset
Objetos simultâneos:
classe combinável
Métodos e recursos
Exemplos
classe de concurrent_vector
A classe de concurrency::concurrent_vector é uma classe do contêiner de sequência que, assim como a classe de std::vector , permite aleatoriamente acessar seus elementos. A classe de concurrent_vector habilita simultaneidade- seguro acrescenta e operações de acesso do elemento. Acrescentar operações não invalidam os ponteiros existentes ou iteradores. As operações de acesso e de passagem do iterador também são simultaneidade- seguras.
Diferenças entre o concurrent_vector e o vetor
A classe de concurrent_vector assemelha-se à classe de vector . A complexidade do anexa, o acesso de elemento, e as operações de acesso de iterador em um objeto de concurrent_vector são as mesmas para um objeto de vector . Os seguintes pontos onde a seguir ilustram concurrent_vector difere de vector:
Anexar, o acesso de elemento, o acesso de iterador, e as operações de passagem do iterador em um objeto de concurrent_vector são simultaneidade- seguras.
Você pode adicionar os elementos somente ao final de um objeto de concurrent_vector . A classe de concurrent_vector não fornece o método de insert .
Um objeto de concurrent_vector não usa semântica de movimentação quando você anexa.
A classe de concurrent_vector não fornece métodos de erase ou de pop_back . Como com vector, use o método de espaço livre para remover todos os elementos de um objeto de concurrent_vector .
A classe de concurrent_vector não armazena seus elementos contiguamente na memória. Consequentemente, você não pode usar a classe de concurrent_vector de todas as maneiras que você pode usar uma matriz. Por exemplo, para uma variável denominada v do tipo concurrent_vector, a expressão &v[0]+2 gerencia comportamento indefinido.
A classe de concurrent_vector define os métodos de grow_by e de grow_to_at_least . Esses métodos lembram ao método de redimensionar , exceto que são simultaneidade- seguros.
Um objeto de concurrent_vector não realocar seus elementos quando você anexa ou o modo de redimensionamento. Isso habilita ponteiros existentes e iteradores permaneça válida durante operações simultâneas.
O tempo de execução não define uma versão especializada de concurrent_vector para o tipo bool.
Operações Simultaneidade-seguras
Todos os métodos que a acrescentam ou aumente o tamanho de um objeto de concurrent_vector , ou acessam um elemento em um objeto de concurrent_vector , são simultaneidade- seguros. A exceção a essa regra é o método de resize .
A tabela a seguir mostra os métodos e os operadores comuns de concurrent_vector que são simultaneidade- seguros.
As operações que o tempo de execução fornece para compatibilidade com o STL, por exemplo, reserve, não são simultaneidade- seguras. A tabela a seguir mostra os métodos e os operadores comuns que não são seguras. simultaneidade-
Operações que alteram o valor dos elementos simultaneidade- existentes não são seguras. Use um objeto de sincronização como um objeto de reader_writer_lock para sincronizar gravação simultâneo e as operações de gravação no mesmo elemento de dados. Para obter mais informações sobre os objetos de sincronização, consulte Estruturas de dados de sincronização.
Quando você converte o código existente que usa vector para usar concurrent_vector, operações simultâneas podem provocar comportamento do aplicativo ser alterado. Por exemplo, considere o seguinte programa que executa duas tarefas simultaneamente em um objeto de concurrent_vector . A primeira tarefa acrescenta os elementos adicionais a um objeto de concurrent_vector . A segunda tarefa computa a soma de todos os elementos no mesmo objeto.
// parallel-vector-sum.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_vector.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
// Create a concurrent_vector object that contains a few
// initial elements.
concurrent_vector<int> v;
v.push_back(2);
v.push_back(3);
v.push_back(4);
// Perform two tasks in parallel.
// The first task appends additional elements to the concurrent_vector object.
// The second task computes the sum of all elements in the same object.
parallel_invoke(
[&v] {
for(int i = 0; i < 10000; ++i)
{
v.push_back(i);
}
},
[&v] {
combinable<int> sums;
for(auto i = begin(v); i != end(v); ++i)
{
sums.local() += *i;
}
wcout << L"sum = " << sums.combine(plus<int>()) << endl;
}
);
}
Embora o método de end é simultaneidade- seguro, simultânea uma chamada ao método de push_back faz com que o valor retornado por end para alterar. O número de elementos que atravessa o iterador não é definido. Em virtude disso, esse programa pode gerar um resultado diferente a cada vez que você executá-lo.
Segurança de exceção
Se uma operação de crescimento ou atribuição gerou uma exceção, o estado do objeto de concurrent_vector torna-se inválido. O comportamento de um objeto de concurrent_vector que está em um estado inválido é indefinido salvo indicação em contrário. No entanto, o destruidor libera memória sempre que o objeto atribui, mesmo se o objeto está em um estado inválido.
O tipo de dados dos elementos de vetor, _Ty, deve atender aos seguintes requisitos. Caso contrário, o comportamento da classe de concurrent_vector é indefinido.
O destruidor não deve lançar.
Se lançará do construtor da opção ou de impressão, o destruidor não devem ser declarados usando a palavra-chave de virtual e deve funcionar corretamente com memória zero inicializada.
[Superior]
classe de concurrent_queue
A classe de concurrency::concurrent_queue , assim como a classe de std::queue , o permite acessar os elementos da frente e do backup. A classe de concurrent_queue habilita operações simultaneidade- seguras de enfileiramento e de retirada da fila. A classe de concurrent_queue também fornece suporte de iterador que não é simultaneidade- seguro.
Diferenças entre o concurrent_queue e a fila
A classe de concurrent_queue assemelha-se à classe de queue . Os seguintes pontos onde a seguir ilustram concurrent_queue difere de queue:
As operações de enfileiramento e de retirada de fila em um objeto de concurrent_queue são simultaneidade- seguras.
A classe de concurrent_queue fornece suporte de iterador que não é simultaneidade- seguro.
A classe de concurrent_queue não fornece métodos de front ou de pop . A classe de concurrent_queue substituirá esses métodos definindo o método de try_pop .
A classe de concurrent_queue não fornece o método de back . Consequentemente, você não pode fazer referência ao final da fila.
A classe de concurrent_queue fornece o método de unsafe_size em vez do método de size . O método de unsafe_size não é simultaneidade-seguro.
Operações Simultaneidade-seguras
Todos os métodos que a linha ou a remover da fila de um objeto de concurrent_queue são simultaneidade- seguros.
A tabela a seguir mostra os métodos e os operadores comuns de concurrent_queue que são simultaneidade- seguros.
Embora o método de empty é simultaneidade- seguro, uma operação simultânea pode fazer com que a fila seja ampliada ou reduzida antes do método de empty retorna.
A tabela a seguir mostra os métodos e os operadores comuns que não são seguras. simultaneidade-
Suporte de iterador
concurrent_queue fornece os iteradores que não são seguras. simultaneidade- Recomendamos que você use esses iteradores depurando somente.
Um iterador de concurrent_queue referem aos elementos na direção somente encaminhada. A tabela a seguir mostra os operadores que da suporte a cada iterador.
Operador |
Descrição |
---|---|
Adiantamentos para o próximo item na fila. Esse operador é sobrecarregado para fornecer o incremento previamente e a semântica de pós-atualização incremento. |
|
Recupera uma referência ao item atual. |
|
Recupera um ponteiro para o item atual. |
[Superior]
classe de concurrent_unordered_map
A classe é uma classe de concurrency::concurrent_unordered_map associativa de contêiner que, assim como a classe de std::unordered_map controle, uma sequência de variar- comprimento dos elementos do tipo std::pair<chave de const, Ty>. Pense de um mapa não ordenada como um dicionário que você pode adicionar um par de chave e o valor para ou pesquisar um valor pela chave. Esta classe é útil quando você tem vários threads ou tarefas que têm que simultaneamente acessar um contêiner compartilhado, o insere nela, ou a ser atualizada.
O exemplo a seguir mostra a estrutura básica para usar concurrent_unordered_map. Este exemplo insere chaves de caractere no intervalo [“a”, “i”]. Como a ordem das operações é indefinido, o valor final de cada chave também é indefinido. No entanto, é seguro ser executados em paralelo as inserções.
// unordered-map-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_map.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
//
// Insert a number of items into the map in parallel.
concurrent_unordered_map<char, int> map;
parallel_for(0, 1000, [&map](int i) {
char key = 'a' + (i%9); // Geneate a key in the range [a,i].
int value = i; // Set the value to i.
map.insert(make_pair(key, value));
});
// Print the elements in the map.
for_each(begin(map), end(map), [](const pair<char, int>& pr) {
wcout << L"[" << pr.first << L", " << pr.second << L"] ";
});
}
/* Sample output:
[e, 751] [i, 755] [a, 756] [c, 758] [g, 753] [f, 752] [b, 757] [d, 750] [h, 754]
*/
Para obter um exemplo que usa concurrent_unordered_map para executar um mapa e reduzir em paralelo a operação, consulte Como realizar operações de mapa e redução em paralelo.
Diferenças entre o concurrent_unordered_map e o unordered_map
A classe de concurrent_unordered_map assemelha-se à classe de unordered_map . Os seguintes pontos onde a seguir ilustram concurrent_unordered_map difere de unordered_map:
erase, bucket, bucket_count, e os métodos de bucket_size são nomeados unsafe_erase, unsafe_bucket, unsafe_bucket_count, e unsafe_bucket_size, respectivamente. A convenção de nomenclatura de unsafe_ indica que esses métodos não se simultaneidade- seguros. Para obter mais informações sobre a segurança de simultaneidade, consulte Operações Simultaneidade-seguras.
As operações de inserção não invalidam os ponteiros existentes ou iteradores, ou para alterar a ordem dos itens já existentes no mapa. A inserção e operações cruzadas podem ocorrer simultaneamente.
o oferece suporte à iteraçãoconcurrent_unordered_map de encaminhamento somente.
A inserção não invalida nem atualiza os iteradores que são retornados por equal_range. A inserção possível adicionar itens diferentes ao final do intervalo. Os pontos de iterador inicial igual a um item.
Para ajudar a evitar o deadlock, nenhum método de propriedades de concurrent_unordered_map um bloqueio ao chamar o alocador de memória, funções hash, ou outro código definido pelo usuário. Além disso, você deve assegurar que a função de hash é avaliada sempre chaves iguais ao mesmo valor. As melhores funções hash distribuição de chaves uniformemente do espaço de código hash.
Operações Simultaneidade-seguras
A classe de concurrent_unordered_map habilita operações simultaneidade- seguras de inserção e de elemento acesso. As operações de inserção não invalidam os ponteiros existentes ou iteradores. As operações de acesso e de passagem do iterador também são simultaneidade- seguras. A tabela a seguir mostra os métodos e operadores de uso geral de concurrent_unordered_map que são simultaneidade- seguros.
count |
find |
||
begin |
empty |
get_allocator |
max_size |
cbegin |
end |
hash_function |
|
cend |
equal_range |
size |
Embora o método de count pode ser chamado com segurança simultaneamente de executar threads, os threads diferentes podem receber resultados diferentes se um novo valor é inserido simultaneamente no contêiner.
A tabela a seguir mostra os métodos e operadores de uso geral que não são seguras. simultaneidade-
clear |
max_load_factor |
rehash |
load_factor |
Além desses métodos, nenhum método que iniciar com unsafe_ também não é simultaneidade- seguro.
[Superior]
classe de concurrent_unordered_multimap
A classe de concurrency::concurrent_unordered_multimap assemelha-se à classe de concurrent_unordered_map exceto que permite vários valores mapear para a mesma chave. Também é diferente de concurrent_unordered_map das seguintes maneiras:
O método de concurrent_unordered_multimap::insert retorna um iterador em vez de std::pair<iterator, bool>.
A classe de concurrent_unordered_multimap não fornece operator[] ou o método de at .
O exemplo a seguir mostra a estrutura básica para usar concurrent_unordered_multimap. Este exemplo insere chaves de caractere no intervalo [“a”, “i”]. concurrent_unordered_multimap habilita uma chave para ter vários valores.
// unordered-multimap-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_map.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
//
// Insert a number of items into the map in parallel.
concurrent_unordered_multimap<char, int> map;
parallel_for(0, 10, [&map](int i) {
char key = 'a' + (i%9); // Geneate a key in the range [a,i].
int value = i; // Set the value to i.
map.insert(make_pair(key, value));
});
// Print the elements in the map.
for_each(begin(map), end(map), [](const pair<char, int>& pr) {
wcout << L"[" << pr.first << L", " << pr.second << L"] ";
});
}
/* Sample output:
[e, 4] [i, 8] [a, 9] [a, 0] [c, 2] [g, 6] [f, 5] [b, 1] [d, 3] [h, 7]
*/
[Superior]
classe de concurrent_unordered_set
A classe de concurrency::concurrent_unordered_set assemelha-se à classe de concurrent_unordered_map exceto que gerencia valores em vez de pares de chave e o valor. A classe de concurrent_unordered_set não fornece operator[] ou o método de at .
O exemplo a seguir mostra a estrutura básica para usar concurrent_unordered_set. Este exemplo insere valores de caractere no intervalo [“a”, “i”]. É seguro ser executados em paralelo as inserções.
// unordered-set-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_set.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
//
// Insert a number of items into the set in parallel.
concurrent_unordered_set<char> set;
parallel_for(0, 10000, [&set](int i) {
set.insert('a' + (i%9)); // Geneate a value in the range [a,i].
});
// Print the elements in the set.
for_each(begin(set), end(set), [](char c) {
wcout << L"[" << c << L"] ";
});
}
/* Sample output:
[e] [i] [a] [c] [g] [f] [b] [d] [h]
*/
[Superior]
classe de concurrent_unordered_multiset
A classe de concurrency::concurrent_unordered_multiset assemelha-se à classe de concurrent_unordered_set exceto que permite valores duplicados. Também é diferente de concurrent_unordered_set das seguintes maneiras:
O método de concurrent_unordered_multiset::insert retorna um iterador em vez de std::pair<iterator, bool>.
A classe de concurrent_unordered_multiset não fornece operator[] ou o método de at .
O exemplo a seguir mostra a estrutura básica para usar concurrent_unordered_multiset. Este exemplo insere valores de caractere no intervalo [“a”, “i”]. concurrent_unordered_multiset habilita um valor ocorra várias vezes.
// unordered-set-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_set.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
//
// Insert a number of items into the set in parallel.
concurrent_unordered_multiset<char> set;
parallel_for(0, 40, [&set](int i) {
set.insert('a' + (i%9)); // Geneate a value in the range [a,i].
});
// Print the elements in the set.
for_each(begin(set), end(set), [](char c) {
wcout << L"[" << c << L"] ";
});
}
/* Sample output:
[e] [e] [e] [e] [i] [i] [i] [i] [a] [a] [a] [a] [a] [c] [c] [c] [c] [c] [g] [g]
[g] [g] [f] [f] [f] [f] [b] [b] [b] [b] [b] [d] [d] [d] [d] [d] [h] [h] [h] [h]
*/
[Superior]
classe combinável
A classe de concurrency::combinable fornece reutilizável, o armazenamento de thread local que permite executar computações refinados e mesclar essas computações em um resultado final. Você pode pensar em um objeto de combinable como uma variável de redução.
A classe de combinable é útil quando você tem um recurso que é compartilhado entre vários threads ou tarefas. Ajuda da classe de combinable você elimina o estado compartilhado fornecendo acesso a recursos compartilhados em um modo lock-partition-id> livre. Em virtude disso, esta classe fornece uma alternativa para usar um mecanismo de sincronização, por exemplo, um mutex, para sincronizar o acesso a dados compartilhados de vários threads.
Métodos e recursos
A tabela a seguir mostra alguns dos métodos importantes da classe de combinable . Para obter mais informações sobre todos os métodos da classe de combinable , consulte Classe combinable.
Método |
Descrição |
---|---|
Recupera uma referência à variável local associado ao contexto do thread atual. |
|
Remove todas as variáveis de thread local do objeto de combinable . |
|
Usa a função fornecida de combinar para gerar um valor final do conjunto de todas as computações de thread local. |
A classe de combinable é uma classe do modelo com parâmetros no resultado final mesclada. Se você chamar o construtor padrão, o tipo de parâmetro do modelo de _Ty deve ter um construtor padrão e um construtor de cópia. Se o tipo de parâmetro do modelo de _Ty não tem um construtor padrão, chame a versão do construtor sobrecarregada que usa uma função de inicialização como o parâmetro.
Você pode armazenar dados adicionais em um objeto de combinable depois que você chama os métodos de combinar ou de combine_each . Você também pode chamar os métodos de combine e de combine_each várias vezes. Se nenhum valor local em um objeto de combinable muda, os métodos de combine e de combine_each gerenciem o mesmo resultado toda vez que são chamados.
Exemplos
Para obter exemplos sobre como usar a classe de combinable , consulte os seguintes tópicos:
[Superior]
Tópicos relacionados
Como usar contêineres em paralelo para aumentar a eficiência
Mostra como usar o contêiner paralelos a eficientemente warehouse e acessam dados em paralelo.Como usar combinável para melhorar o desempenho
Mostra como usar a classe de combinable para eliminar o estado compartilhado, e melhoram assim o desempenho.Como usar combinável para combinar conjuntos
Mostra como usar uma função de combine para mesclar conjuntos de thread local de dados.Biblioteca de padrões paralelos (PPL)
Descreve o PPL, que fornece um modelo de programação obrigatório que promova a escalabilidade e a facilidade de uso para desenvolver aplicativos simultâneos.
Referência
Classe concurrent_unordered_map
Classe concurrent_unordered_multimap
Classe concurrent_unordered_set