cas
(requer Workerman versão >= 3.3.0)
bool \GlobalData\Client::cas(string $key, mixed $old_value, mixed $new_value)
Substituição atômica, onde$new_value substitui$old_value.
Somente pode-se escrever o valor se, após a última leitura feita pelo cliente atual, o valor correspondente a essa chave não tiver sido modificado por outros clientes.
Parâmetros
$key
Chave. (por exemplo$global->abc,abc é a chave)
$old_value
Valor antigo
$new_value
Novo valor
Valor de retorno
Retorna true se a substituição for bem-sucedida, caso contrário, retorna false.
Descrição:
Quando múltiplos processos operam simultaneamente em uma mesma variável compartilhada, às vezes é necessário considerar problemas de concorrência.
Por exemplo, os processos A e B estão simultaneamente adicionando um membro à lista de usuários.
A e B atualmente possuem a lista de usuários como$global->user_list = array(1,2,3).
O processo A modifica a variável$global->user_list para adicionar um usuário 4.
O processo B modifica a variável$global->user_list para adicionar um usuário 5.
O processo A define a variável$global->user_list = array(1,2,3,4) com sucesso.
O processo B define a variável$global->user_list = array(1,2,3,5) com sucesso.
Neste momento, a variável definida pelo processo B sobrepõe a variável definida pelo processo A, resultando em perda de dados.
O acima ocorre porque a leitura e a definição não são operações atômicas, levando a problemas de concorrência.
Para resolver esse tipo de problema de concorrência, pode-se usar a interface de substituição atômica cas.
A interface cas, antes de alterar um valor,
verifica se o valor foi modificado por outros processos com base em$old_value.
Se houve alteração, não substitui e retorna false. Caso contrário, substitui e retorna true.
Veja o exemplo abaixo.
Atenção:
Em alguns dados compartilhados, a sobreposição concorrente não é um problema, como, por exemplo, o maior lance atual em um sistema de leilão ou o estoque atual de um produto.
Exemplo
$global = new GlobalData\Client('127.0.0.1:2207');
// Inicializa a lista
$global->user_list = array(1,2,3);
// Adiciona um valor à user_list de forma atômica
do
{
$old_value = $new_value = $global->user_list;
$new_value[] = 4;
}
while(!$global->cas('user_list', $old_value, $new_value));
var_export($global->user_list);