cas

(Workerman 버전 >= 3.3.0 이상 필요)

bool \GlobalData\Client::cas(string $key, mixed $old_value, mixed $new_value)

원자적으로 대체하여 $new_value$old_value를 대체합니다.
현재 클라이언트가 특정 키 값의 값을 다른 클라이언트에 의해 변경되지 않은 경우에만 값을 쓸 수 있습니다.

매개변수

$key

키 값입니다. (예를 들어, $global->abc에서 abc가 키 값입니다.)

$old_value

이전 데이터

$new_value

새로운 데이터

반환 값

대체가 성공하면 true를, 그렇지 않으면 false를 반환합니다.

설명:

여러 프로세스가 동시에 동일한 공유 변수를 조작할 때 종종 동시성 문제를 고려해야 합니다.

예를 들어 A와 B 두 프로세스가 동시에 사용자 목록에 멤버를 추가합니다.
현재 A와 B 프로세스의 사용자 목록이 $global->user_list = array(1,2,3)입니다.
A 프로세스는 $global->user_list 변수를 조작하여 사용자 4를 추가합니다.
B 프로세스는 $global->user_list 변수를 조작하여 사용자 5를 추가합니다.
A 프로세스는 변수를 설정하여 $global->user_list = array(1,2,3,4) 성공합니다.
B 프로세스는 변수를 설정하여 $global->user_list = array(1,2,3,5) 성공합니다.
이때 B 프로세스가 A 프로세스가 설정한 변수를 덮어쓰면서 데이터가 손실됩니다.

위와 같이 읽고 설정이 원자적인 작업이 아니라 동시성 문제가 발생합니다.
이러한 동시성 문제를 해결하기 위해 cas(Compare and Swap) 원자적 대체 인터페이스를 사용할 수 있습니다.
cas 인터페이스는 값을 변경하기 전에 $old_value를 기반으로 이 값이 다른 프로세스에 의해 변경되었는지 확인하고, 변경되었으면 교체하지 않고 false를 반환합니다. 그렇지 않으면 true를 반환합니다.

참고:
일부 공유 데이터가 동시에 덮어쓰여도 문제가 되지 않습니다. 예를 들어 경매 시스템의 현재 최고 입찰가, 상품의 현재 재고 등이 해당됩니다.

예시

$global = new GlobalData\Client('127.0.0.1:2207');

// 리스트 초기화
$global->user_list = array(1,2,3);

// user_list에 값을 원자적으로 추가
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);