

Mutex는 Data race를 방지하기 위해 사용한다.
프로그램의 실행 결과가 일정하지 않고, 실행 순서에 영향을 받는 상태
운이 좋게 코드가 정상적으로 실행되기도 하고 나쁘면 잘못된 결과가 나오기도 한다.
ex) 스레드A와 B가 있는 프로세스가 있고, 해당 프로세스의 공유자원 x가 0으로 초기화되어 있었다고 가정해보자.
우리가 원하는 프로세스의 결과는 x가 3이 되는 것일 것이다.
성공 case 1
1. A : 공유자원 x 값 읽어오기
2. A : x += 1
3. B : 공유자원 x 값 읽어오기 (A의 결과가 반영된 값을 읽어오게 됨)
4. B : x += 2
=> x = 3
성공 case 2
1. B : 공유자원 x 값 읽어오기
2. B : x += 2
3. A : 공유자원 x 값 읽어오기 (B의 결과가 반영된 값을 읽어오게 됨)
4. A : x += 1
=> x = 3
실패 case 1
1. B : 공유자원 x 값 읽어오기
2. A : 공유자원 x 값 읽어오기
3. B : x += 2
4. A : x += 1
=> x = 1
실패 case 2
1. B : 공유자원 x 값 읽어오기
2. A : 공유자원 x 값 읽어오기
3. A : x += 1
4. B : x += 2
=> x = 2
따라서 우리는 Mutex를 통해 값을 동기화 시켜주어야 한다.
즉, 해당 공유 자원에 접근 하는 동안에는 다른 스레드에서 이 값을 읽거나 쓰지 못하도록 점유함으로써 data race를 방지 !

monitoring을 하는 스레드에서 사용하기 위한 구조체
main에서는 스레드 생성 전에 lock을 해주고, 스레드를 모두 생성 및 시작 시점 측정 뒤 unlock을 해준다.
모든 스레드는 처음 처음에 m_start를 lock을 하도록 하여 모든 스레드가 생성될 때까지 waiting을 할 수 있다. 다른 스레드들도 바로 시작할 수 있도록 lock을 잡은 뒤 바로 unlock !num_of_philo, time_to_die 등의 변수가 mutex가 아닌 이유?
이 변수들도 공유 자원이고, 다른 스레드에서 이 변수에 접근하는 것은 맞지만 모든 스레드들이 READ만 진행하므로 동시에 접근한다고 해도 문제가 되지 않음 !

fork가 결국 0 아니면 1의 상태로 점유 여부가 저장되므로 m_fork를 그 자체로 fork로 쓰는 경우도 있다.

fsanitize=thread -g 옵션으로 data race check 가능하다 !
처음 코드를 작성했을 때부터 완전한 설계가 되어 있었던 것은 아니고
코드를 구현하다가 data race가 발생하고 있는지 여부를 확인하고 필요한 mutex를 하나씩 추가해주면서 구조체를 구축하였다.
🦋 Philosophers repo address
https://github.com/kyj93790/42-cursus/tree/master/Philosophers