재진입성 (再進入性, 영어: reentrancy)은 컴퓨터 과학에서 함수, 서브루틴, 또는 프로그램의 특성 중 하나로, 해당 코드가 현재 실행 중이거나 중단된 상태에서도 안전하게 다시 호출되거나 재시작될 수 있는 능력을 의미한다. 즉, 여러 스레드나 인터럽트 핸들러에 의해 동시에 또는 순서 없이 호출되어도 올바른 동작을 보장하며, 내부 상태가 손상되지 않는 특성을 말한다.
컴퓨터 과학에서의 재진입성
재진입성 함수는 다음과 같은 특징을 가진다.
- 상태 비저장 (Stateless) 또는 지역 상태 사용: 전역 변수나 정적(static) 변수와 같은 공유 데이터를 수정하지 않거나, 수정하더라도 이를 보호하기 위한 특별한 메커니즘을 사용하지 않는다. 필요한 모든 데이터는 인자로 전달받거나, 호출될 때마다 새로 생성되는 스택 기반의 지역 변수로 처리한다.
- 자기 봉쇄적 (Self-contained): 함수는 자신의 실행 환경 외부의 어떠한 데이터도 변경하지 않으며, 다른 함수의 실행에 영향을 주지 않는다.
- 비-정적 데이터 의존: 함수 내부에서 선언된 정적 변수나 전역 변수를 사용하더라도, 해당 변수를 수정하지 않고 읽기 전용으로만 사용한다. 또는 스레드 로컬 스토리지(thread-local storage)와 같이 각 호출마다 독립적인 메모리 공간을 할당하는 방식을 사용한다.
- 비-재진입 함수 호출 금지: 재진입성이 보장되지 않는 다른 함수(예: 록(lock)을 사용하는 표준 입출력 함수)를 호출하지 않아야 한다.
재진입성은 특히 다중 스레드 환경, 운영 체제의 커널 코드, 인터럽트 서비스 루틴(ISR) 등에서 매우 중요한 개념이다. 예를 들어, 인터럽트 핸들러가 현재 실행 중인 코드와 동일한 함수를 호출해야 할 때, 해당 함수가 재진입 가능해야만 데이터 손상이나 예상치 못한 동작을 방지할 수 있다.
재진입성 확보 방법
- 지역 변수만 사용: 모든 필요한 변수를 스택에 할당되는 지역 변수로 선언하고 사용한다.
- 인자를 통한 데이터 전달: 함수가 필요로 하는 모든 데이터는 인자를 통해 명시적으로 전달받는다.
- 전역/정적 변수 사용 회피: 전역 변수나 정적 변수를 아예 사용하지 않거나, 사용하더라도 값을 변경하지 않고 읽기 전용으로만 사용한다.
- 비-재진입 함수 호출 피하기: 내부적으로 재진입성이 보장되지 않는 라이브러리 함수나 시스템 호출을 사용하지 않는다.
비-재진입성의 예시
다음과 같은 상황의 함수는 재진입성이 없다고 볼 수 있다.
- 내부적으로 정적 변수를 수정하는 함수. (예: 난수 생성 함수 중 일부)
- 전역 변수를 수정하거나 의존하는 함수.
- 파일 시스템이나 네트워크 소켓 등 공유 자원에 접근하며, 그 접근을 적절히 동기화하지 않는 함수. (이 경우 스레드 안정성과도 연관됨)
재진입성과 다른 개념과의 관계
- 스레드 안정성 (Thread Safety): 스레드 안정성은 여러 스레드가 동시에 함수나 데이터 구조에 접근해도 안전하게 동작함을 의미한다. 재진입성은 스레드 안정성을 달성하는 한 가지 강력한 방법이지만, 재진입성이 반드시 스레드 안정성을 의미하지는 않는다. 예를 들어, 뮤텍스(mutex)를 사용하여 공유 자원에 대한 접근을 동기화하는 함수는 스레드 안정성을 가질 수 있지만, 뮤텍스를 획득한 상태에서 다시 자신을 호출하려고 할 경우 교착 상태(deadlock)에 빠질 수 있으므로 재진입성이 없다고 볼 수 있다. 그러나 일반적으로 순수한 의미의 재진입 함수는 별도의 동기화 메커니즘 없이도 스레드 안전하다.
- 순수 함수 (Pure Function): 순수 함수는 동일한 입력에 대해 항상 동일한 출력을 반환하며, 함수 외부의 어떤 상태도 변경하지 않는 부작용(side effect)이 없는 함수이다. 순수 함수는 모든 요구 사항을 충족하므로 항상 재진입 함수이자 스레드 안정 함수이다.
- 상호 배제 (Mutual Exclusion): 록(lock)이나 세마포어(semaphore)와 같은 상호 배제 메커니즘은 공유 자원에 대한 접근을 제어하여 스레드 안정성을 보장한다. 그러나 이러한 메커니즘은 일반적으로 재진입성과는 반대되는 개념으로 이해된다. 즉, 록을 사용하는 함수는 록을 획득한 상태에서 자신을 재귀적으로 호출하거나 다른 스레드에 의해 동시에 호출될 경우 문제가 발생할 수 있다.
같이 보기
- 스레드 안정성
- 순수 함수
- 동시성 (Concurrency)
- 인터럽트 (Interrupt)
- 교착 상태 (Deadlock)