Saída:
A saída deste exemplo mostra o comportamento indefinido do aplicativo, pois a saída do código é 0 ou 10. Isso aconteceu porque os tópicos estavam executando simultaneamente e o comando de leitura poderia ter sido feito durante a execução do comando de gravação. Dessa forma, obtivemos um resultado incompleto na saída.
O STD Atomic pode resolver esse problema e pode fazer com que os comportamentos indefinidos no aplicativo sejam bem definidos. Para implementar isso, simplesmente fazemos uma pequena alteração ao inicializar e definir os valores e os tipos de dados das variáveis definidas usando “std :: atomic”. Definimos a variável "A" e "B" como as variáveis atômicas por "Nome da variável atômica STD :: Atomic". Também fazemos uma pequena mudança na função de gravação em que, anteriormente, simplesmente atribuímos os valores a A e B usando o operador de atribuição "=". Mas aqui, atribuímos os valores usando o “Nome da variável. Método da loja (valor) ”. Usamos o “nome variável. load () ”na função de leitura. O resto é o mesmo que no exemplo anterior.
Os valores na saída são lidos e escritos de uma maneira bem definida. E a multithreading também é suportada aqui.
Libere e adquirir pedidos com memória (modelo)
O modelo de memória pode ter um enorme impacto nas funções de leitura e gravação do std atomic. O modelo de memória é uma função padrão que garante consistência sequencial de pedidos. Um dos modelos atômicos mais interessantes é o modelo de liberação e aquisição, onde podemos armazenar a liberação de pedidos de memória para o primeiro thread e a ordem de memória adquirida para o segundo tópico, o que significa que qualquer armazenamento/gravação atômico ou não atômico é feito primeiro no primeiro tópico antes do segundo tópico, eu.e. carregar.
Portanto, no exemplo, podemos até alterar a variável atômica "A" para não atômica e a segunda variável "B" é mantida atômica. Na função de gravação, armazenamos a variável não atômica "A" simplesmente atribuindo a ela qualquer valor, e.g. 30. E armazenamos adequadamente o valor da variável atômica "B" usando "B. Store (Valor, STD :: Mememy_order_release) ”. O mesmo é feito na função de leitura também onde usamos o “std :: cout < Saída:
A atomicidade da operação ainda é mantida com o modelo de release e memória adquirida, mesmo quando tivemos uma variável x não atômica. Isso aconteceu por causa dos y's (atômico.armazenar) que garantiu a manutenção da consistência seqüencial.
Modelo de troca
Troca significa quando trocamos o valor de uma variável (atômica) a outro valor. Em troca, o valor é trocado primeiro e depois o valor anterior que está sendo trocado pelo novo é devolvido. Depois que o valor é trocado, reflete sobre todas as operações subsequentes a esse valor. Vamos implementar essa troca de variáveis atômicas com a ajuda de um exemplo.
Neste exemplo, primeiro introduzimos a variável atômica global Foobar, que tem algum valor igual a "15". Em geral, fazemos um thread como Thread1 e atribuímos um valor inteiro igual a 2. Então, no loop for, definimos o índice de 0 a 100 vezes. Em seguida, substituímos o valor da variável foobar para 2 usando “foobar. Exchange (valor) ”. Depois disso, saímos do loop e carregamos o valor da variável foobar para imprimi -lo. Depois de carregar o valor de foobar, agora trocamos seu valor com 18 pelo “.Exchange (valor a ser substituído) ”Método. E, novamente, carregue os valores do foobar e os exiba usando o método de impressão.
Aqui neste exemplo, o tópico deve trocar os valores por centenas de vezes e o valor de Foobar é trocado de 15 a 28. Qualquer operação após esta troca retorna o mesmo valor que pode ser visto na saída.
Buscar
Buscar é o mesmo que a função de troca que escreve os valores e retorna os valores previamente buscados. Esta operação busca o valor que é armazenado antes de qualquer operação ser aplicada a ela. Agora, implementamos a busca de add e busca e buscar neste exemplo. Definimos uma variável atômica com o tipo de dados não assinado como “contagem” e inicializamos a contagem com zero. Em seguida, criamos duas funções - uma para buscar add e outra para buscar subtração. Executamos o balcão de incremento 1 para add e decrementos 1 para subtrair em ambas as funções. Em seguida, imprimimos esses valores das funções fetch_add e fetch_sub.
A função fetch_add retornou 0 e 1 como os valores anteriores antes do incremento. Da mesma forma, o Fetch_sub retornou 2 e 1 como os valores armazenados anteriormente antes da subtração ou decréscimo de um.
Conclusão
Implementamos as operações básicas em "std :: atomic" neste artigo. Aprendemos como podemos lidar com os problemas em aplicativos multithreading usando o std atomic. Implementamos os vários exemplos em C ++ para as diferentes funções, como buscar, troca, leitura/escrita e modelo de memória do std atomic para garantir a consistência seqüencial e comportamentos bem definidos do código para aplicativos multithread.