프로그래밍시스템/백엔드 및 임베디드 개발자

전역 변수(static)를 Rust에서 사용하는 규칙에 대해 설명해 주세요. 동시에 접근할 때 안전성은 어떻게 보장되며, 초기화 및 동기화의 다양한 방법은 어떻게 다릅니까?

Hintsage AI 어시스턴트로 면접 통과

답변

Rust에서는 전역 변수를 키워드 static을 사용하여 선언합니다. 이러한 변수는 프로그램 실행 시간 동안 살아 있습니다. 기본적으로 변경할 수 없는 static에는 안전하게 접근할 수 있지만, 변경할 수 있는 변수에는 unsafe를 사용해야 합니다. 컴파일러는 스레드 간 경쟁이 없음을 보장할 수 없습니다.

변경할 수 있는 전역 변수에 안전하게 접근하기 위해서는 특별한 래퍼 타입(Mutex, RwLock, Atomic* 타입 또는 외부 crate(lazy_static, once_cell)를 사용합니다. 초기화는 "게으른" 방식으로, 첫 호출 시 객체 생성을 연기합니다.

예시:

static COUNTER: AtomicUsize = AtomicUsize::new(0); static ref CONFIG: Config = read_config(); // lazy_static 또는 once_cell을 사용하여

트랩 질문

단일 스레드에서만 사용될 경우, 특별한 타입 없이 변경 가능한 전역 변수를 선언할 수 있습니까? unsafe를 작성해야 합니까?

답변: 변경 가능한 전역 변수를 수정할 때, 로직이 단일 스레드라고 해도 컴파일러는 unsafe를 사용하라고 요구합니다. 이는 모든 static mut에 대한 일반 요구 사항입니다. 변수 자체가 동기화 구조(Mutex, 원자 변수 등)에 감싸져 있을 때만 컴파일러는 안전한 접근을 허용합니다.

static mut VALUE: i32 = 0; unsafe { VALUE += 1; }

주제에 대한 세부 사항을 모르고 발생한 실제 오류 사례


이야기

웹 서비스에서 전역 캐시를 초기화할 때 문자열을 사용하는 일반 static 변수를 사용했습니다. 여러 스레드가 동시에 쓰면서 메모리 "비트"와 스레드 경합으로 인해 애플리케이션이 다운되는 문제가 발생했습니다.


이야기

Rust로 작성된 명령줄 유틸리티에서 동기화 없이 정적 변수를 수정했는데, "main을 통해서만 작동합니다"라는 이유였습니다. 나중에 멀티스레딩을 위해 코드를 수정했지만, global mutable state를 잊어버려서 매우 찾기 힘든 버그가 발생했습니다.


이야기

임베디드 프로그램에서 static CONFIG를 함수로 초기화하는데 잘못되어, 정확히 한 번만 호출된다는 보장을 하지 않았습니다. 결과적으로 일부 코드가 초기화되지 않은 구성(null reference)에게 접근하게 되었습니다.