@cmpxchgStrong — 강한 원자적 비교-교환 연산
@cmpxchgStrong — 강한 원자적 비교-교환 연산
멀티스레드에서 여러 스레드가 같은 값을 동시에 바꾸려 할 때, "지금 값이 내가 기대하는 값이라면 새 값으로 바꿔라"라는 연산이 필요할 때가 있어요. 그걸 안전하게, 그러니까 중간에 다른 스레드가 끼어들지 못하게 하는 원자적 연산이 바로 @cmpxchgStrong이에요. 현재 값이 기대하는 값과 같으면 새 값으로 바꾸고 null을, 다르면 그대로 둔 채 현재 값을 돌려줘요.
본문
@cmpxchgStrong은 강한(strong) 원자적 비교-교환(compare-and-exchange) 연산을 수행해요. 현재 값이 주어진 기대값(expected_value)과 같으면 연산은 null을 돌려주죠. 원자적 버전이라는 점만 빼면 아래 코드와 정확히 같은 동작이에요:
fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_value: T) ?T {
const old_value = ptr.*;
if (old_value == expected_value) {
ptr.* = new_value;
return null;
} else {
return old_value;
}
}
함수 시그니처는 이렇게 생겼어요:
@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T
cmpxchg를 재시도 루프(retry loop) 안에서 쓴다면 @cmpxchgWeak이 더 나은 선택이에요. 기계 명령어로 더 효율적으로 구현될 수 있거든요. 강한 버전은 "성공이 보장될 때까지 반복"이라는 의미를 담고 있어 한 번만 시도하는 흐름에 어울려요.
몇 가지 타입 제약이 있어요:
T는 포인터,bool, 정수, enum, 또는 packed struct여야 해요.@typeInfo(@TypeOf(ptr)).pointer.alignment는@sizeOf(T)보다 크거나 같아야 해요.AtomicOrder는@import("std").lang.AtomicOrder에서 찾을 수 있어요.
함께 보면 좋은 연산들도 있어요:
@atomicStore@atomicLoad@atomicRmw@cmpxchgWeak
더 알아보기 (Learn more)
@cmpxchgStrong은 원자적 메모리 연산 중 하나일 뿐이에요. 재시도 루프에는 더 효율적인 @cmpxchgWeak, 읽기·쓰기·읽고-수정-쓰기에는 @atomicLoad·@atomicStore·@atomicRmw를 함께 익혀 두면 동시성 코드를 짤 때 훨씬 수월해져요.