project/개발 업무

defer로 인해 lock의 범위가 넓어져 발생한 문제 분석

lgvv 2026. 3. 26. 17:02

defer로 인해 lock의 범위가 넓어져 발생한 문제 분석

 

 

동시성 코드에서 lock은 가장 직관적인 장치 중 하나로 여러 스레드가 같은 상태를 동시에 읽고 쓰면 race condition이 발생할 수 있기 때문에 공유 자원을 보호하기 위해 lock을 사용.

 

문제는 아래의 코드 패턴은 락의 범위를 함수 끝까지 늘려서 이 경우 후속 로직에서 lock을 다시 잡아야 하는 코드가 존재면 문제가 발생할 수 있음.

func foo() {
    lock.lock()
    defer { lock.unlock() }
    
    // do something
}

 

 

문제가 발생하는 코드 예시

락을 잡은 채 기다리는 구조가 생기면 장기 대기나 데드락으로 이어질 수 있음.
특히 코드와 로직이 복잡할수록 원인이 코드 한가운데에 숨어 있어 발견하기 어려움.

func someFunction() {
    lock.lock()
    defer { lock.unlock() }

    // 상태 변경
    isCompleted = false
    
    // callback이 signal 해줘야 함
    finished.wait()
}

func callback() {
    lock.lock()
    defer { lock.unlock() }
    
    // 상태 변경
    isCompleted = true

    finished.signal()
}

 

 

lock은 상태만 보호하기

 

락의 역할은 공유 상태를 안전하게 읽고 쓰는 것이 목적이라서 가급적 짧게 유지해야 함.

defer로 lock 범위가 넓어진 상태에서 오래 기다릴 수 있는 작업까지 임계구역에 들어갈 경우 lock이 상태 보호의 도구를 넘어 흐름을 차단하는 장치로 동작하게 됨.

 

따라서 lock은 상태를 보호하기 위해서 짧게 사용하고, 대기하는 작업은 반드시 lock 밖에서 사용하기.