Philosophers
멀티 스레드
**식사하는 철학자 문제(Dining Philosophers Problem)**를 구현하는 과제이다. 동시성 환경에서 공유 자원을 여러 스레드가 경쟁할 때 발생하는 **데이터 레이스(data race)**와 **데드락(deadlock)**을 직접 마주하고, 이를 올바르게 제어하는 방법을 학습한다.
- 개발 기간: 2024.02 ~ 2024.03
- 과정: 42 Seoul Inner Circle
- 언어: C
- GitHub: https://github.com/Budnarae/42_innercircle_course/tree/main/Philosophers
개요
원탁에 N명의 철학자가 앉아 있고, 각 철학자 사이에는 포크가 하나씩 놓여 있다. 철학자는 양쪽 포크를 모두 집어야 식사를 할 수 있으며, 식사를 마치면 포크를 내려놓고 잠을 자다가 다시 생각한다. 일정 시간 내에 식사를 하지 못한 철학자는 굶어 죽는다.
포크는 인접한 두 철학자가 공유하는 자원이므로, 동기화 없이 구현하면 두 스레드가 같은 포크를 동시에 집으려는 데이터 레이스가 발생한다. 또한 모든 철학자가 동시에 왼쪽 포크만 집고 오른쪽 포크를 기다리면 아무도 진행하지 못하는 데드락 상태에 빠진다.
실행 방법
./philo [철학자 수] [죽기까지 걸리는 시간(ms)] [식사 시간(ms)] [수면 시간(ms)] [목표 식사 횟수(선택)]목표 식사 횟수를 입력하지 않으면 철학자들은 무한히 식사를 반복한다. 아래는 2명의 철학자가 각각 4번 식사를 완료할 때까지 시뮬레이션하는 예시이다.
./philo 2 450 200 200 4실행 결과를 philosopher visualizer에 붙여넣으면 시뮬레이션을 시각적으로 확인할 수 있다.
구현 내용
스레드 생명주기 관리
각 철학자를 pthread로 생성하여 독립적인 스레드로 동작시킨다. 각 스레드는 생각 → 포크 집기 → 식사 → 포크 내려놓기 → 수면의 루프를 반복한다.
mutex 기반 포크 동기화
각 포크를 mutex로 보호하여, 한 철학자가 포크를 집고 있는 동안 다른 철학자가 같은 포크를 집지 못하도록 한다. 이를 통해 데이터 레이스를 방지한다.
데드락 회피 전략
모든 철학자가 같은 순서로 포크를 집으면 데드락이 발생한다. 이를 피하기 위해 짝수/홀수 번호 철학자가 포크를 집는 순서를 다르게 하는 등의 전략을 적용했다.
모니터링 루틴
별도의 감시 스레드가 각 철학자의 마지막 식사 시각을 주기적으로 확인하여 사망 조건을 판정한다. 목표 식사 횟수가 설정된 경우 모든 철학자가 해당 횟수를 채웠는지도 감시한다.
보너스: 멀티프로세스 + 세마포어 모델 (philo_bonus)
philo_bonus는 스레드 대신 멀티프로세스로, mutex 대신 세마포어로 같은 문제를 다시 구현한 버전이다. 각 철학자가 별도의 프로세스로 동작하며, 세마포어로 포크 자원의 접근을 제어한다.