본문 바로가기
42seoul/circle-3

[Philosophers] 1. 과제 해결하기

by saniii 2022. 5. 8.

 

# 철학자들은 스레드로 구현되어 있다. 

* 쓰레드 : 어떤 프로그램 내에서 실행되는 흐름의 단위 

  • 운영체제의 일부인 스케줄러에 의해 독립적으로 관리될 수 있는 프로그래밍 된 명령어의 가장 작은 시퀀스
  • 하나의 프로그램은 하나 이상의 프로세스를 가지고 하나의 프로세스는 하나 이상의 스레드를 가진다. 
* 프로세스 : 컴퓨터 프로그램의 인스턴스로 하나 이상의 스레드를 통해 실현된다. 
    -  메모리에 적재되고 CPU 자원을 할당받아 프로그램이 실행되고 있는 상태 
* 스레드 vs 프로세스
프로세스는 실행될 때 운영체제로부터 각각 독립된 메모리 영역을 할당받는다. 스레드는 한 프로세스 내에서 동작되는 흐름으로 프로세스네에서 stack영역만 별도로 할당 받는다. 부모프로세스의 코드, 데이터, 힙 영역은 공유한다. 즉, 프로세스내에서 자식 스레드들은 서로 주소 공간이나 자원들을 공유하면서 실행될 수 있다. 

 

 

# 철학자들은 동시에 같은 포크를 사용할 수 없다. 

포크를 뮤텍스로 보호하여 포크를 동시에 사용할 수 없도록 한다. 

 

* 동기화 문제

  • 동기화 synchronization : 프로세스, 스레드들이 수행되는 시점을 조절하여 서로가 알고 있는 정보가 일치하는 것
  • race condition(data race) 경쟁 상태 : 두 개 이상의 프로세스, 쓰레드가 동기화없이 공유자원에 접근하는 현상
  • 공유자원이 동기화되지 않으면 date race로 인해 데이터의 일관성이 유지되지않는다. 

 

* 뮤텍스, mutex : 공유된 자원의 데이터를 여러 쓰레드가 접근하는 것을 막는 것

  • critical section을 가지는 쓰레드들의 러닝타임이 서로 겹치지 않게 해주는 기법
  • 1개의 스레드만 공유 자원에 접근할 수 있게 한다. (이진 세마포어)
  • 자원을 점유하고 있는 대상이 lock할 수 있는 권한을 가지고 있어 자원을 점유하기 시작할 때 들어가서 lock을 건다. 다른 대상들은 unlock상태가 될 때까지 기다렸다가 나중에 해당 공유자원에 접근할 수 있게 된다. 
* critical section 임계구역 : 하나의 스레드만이 진입해야하는 특정 코드 구역
       - 공유 자원의 변경이 일어날 수 있는 구간
이 구역을 pthread_mutex_lock/unlock으로 감싸면  

세마포어 semaphore : 공유된 자원의 데이터를 여러 프로세스가 접근하는 것을 막는 것
- 이를 위해 현재 공유 자원의 상태를 나타내는 카운터 변수를 사용하고 이 변수는 운영체제 혹은 커널에 값으로 저장되어 각 프로세스가 이를 확인, 변경할 수 있다. 이 변수 값을 확인하면서 자원을 사용할 수 있을 때는 즉시 사용하고, 누군가 사용중일 때는 일정시간을 기다렸다가 사용한다.
- 0, 1 보다 더 큰 숫자를 가질 수 있어서 1개의 프로세스만이 자원을 점유하지는 않는다. 카운터 변수의 값이 해당 공유자원에 접근할 수 있는 임계치가 되면 이를 저장하여 접근할 수 있는 프로세스의 개수를 통제할 수 있다. 

* 뮤텍스 vs 세마포어
>> 세마포어는 뮤텍스가 될 수 있지만 뮤텍스는 세마포어가 될 수 없다. 
     (뮤텍스는 상태가 0 1 뿐인 이진형 세마포어이다.)
>> 세마포어는 소유할 수 없는 반면, 뮤텍스는 소유가 가능하며 소유주가 이에 대한 책임
>> 세마포어는 파일 형태로 존재하며, 전 시스템 범위, 뮤텍스는 프로세스 범위이며 프로세스 종료 시 초기화 

 

 

 

# 철학자 중 굶어 죽는 철학자가 발생하면 안된다. 

* 교착상태 (deadlock) : 두 개 이상의 작업이 서로 상대방의 작업이 끝나기를 기다리고 있어 결과적으로 아무것도 완료되지 못하는 상태

  • 상호배제 (Mutual Exclusion)
    • 한 번에 한 개의 프로세스만이 공유 자원을 사용할 수 있어야 한다.
    • ex : 하나의 포크는 한명의 철학자만 들 수 있다. 
  • 점유대기 (Hold and Wait)
    • 최소한 하나의 자원을 점유하고 있으면서 다른 프로세스에 할당되어 사용되고 있는 자원을 추가로 점유하기 위해 대기하는 프로세스가 있어야한다. 
    • ex : 왼쪽 포크를 들고 오른쪽 포크를 기다린다.
  • 비선점 (No preemption)
    • 다른 프로세스에 할당된 자원은 사용이 끝날 떄까지 강제로 빼앗을 수 없다.
    • ex : 다른 철학자가 들고 있는 포크를 강제로 뺏어올 수 없다.  
  • 순환대기 (Circular wait)
    • 공유자원과 공유자원을 사용하기 위해 대기하는 프로세스들이 원형으로 구성되어 있어 자신에게 할당된 자원을 점유하면서 앞이나 뒤에 있는 프로세스의 자원을 요구해야한다. 
    • ex : 하나의 포크를 두고 앞뒤(포크 양 옆의)의 철학자가 경쟁(?)한다. 

>> 해결 방법

  • 예방 
    • 교착 상태가 발생하기 전에 미리 조치를 취하여 교착 상태 발생 조건 중 하나 이상을 제거한다.
  • 회피
    • 프로세스가 자원을 요구할 때, 시스템은 자원을 할당한 후에도 안정 상태로 남아있는가를 확인하여 교착 상태를 회피한다.
  • 발견
    • 교착상태가 발생하면 빠르게 발견하여 문제를 해결한다. 
  • 회복
    • 교착을 일으킨 프로세스를 종료하거나 할당된 자원을 해제하여 회복한다.

 

이중 예방 기법 중 순환대기를 깨는 방법을 사용하여 해결하자. 

>> 철학자들을 홀수id와 짝수id로 나누어 홀수 번호는 쓰레드가 생성되자마자 포크를 들고 짝수 번호는 쓰레드가 생성되고 1ms후에 포크를 들도록 한다.(들 수 있다면)

 

 

 

 

# 출력되는 메세지는 다른 메세지와 섞이면 안된다. 

출력하는 동안을 임계구역으로 뮤텍스를 걸어 다른 메세지와 섞여서 출력되지 않도록 한다. 

( printf의 앞뒤로 mutex lock과 unlock걸기 )

 

 

 

 

 

# 모든 로직을 무한 반복돌렸는데 왜 무한 반복돌리는 로직들이 섞여서 실행될까?

(함수 1, 2, 3, ... 을 무한루프안에 가둔채로 실행했는데 어쨰서 1만 계속되지 않고 1 2 3 ... 이 번갈아가며 실행될까?)

 

  • thread switch : 
  • context switch : CPU 제어권을 한 프로세스에서 다른 프로세스로 넘겨주는 과정
* thread switch vs context switch
스레드간에는 자원을 공유하기 때문에 context switch보다 thread switch의 속도가 빠르다. 
  • 스레드 간의 통신
    • 공유메모리 기법 : 모든 프로세스가 접근 가능하다.
      • 빠르다.
      • 동기화 처리 필요
    • 메세지 교환 기법 : 필요한 공유자원을 그때 그때 프로세스 사에에서 전달한다. 
      • 동기화 신경쓸 필요 없음
      • 느리다. 

 

 

 

# (pthread_) join과 detach의 차이 

  • 두 함수 모두 스레드가 종료하면 사용된 자원에 대해 즉시 free한다. 
  • join은 진짜 종료될 때까지 기다린다. 
  • detach는 안기다리고 다음 코드부터 실행한다. 

 

 

 

 

# pthread_mutex_unlock을 두번이나 하는 것에 대하여 

철학자가 1명일 경우를 생각하다보니 포크를 lock한 채로 죽으면 어떻게 되는 거지? 라는 생각이 들었다. 이런 경우는 철학자가 한명인 경우에 국한 되는 것이 아니라 여러명일 때도 발생할 수 있다. 포크를 하나만 들고 기다리다가 굶어죽는 경우.

 

pthread_mutex_unlock의 man 페이지를 찾아봤을 때 이미 풀려있는 mutex를 또 다시 unlock하는 경우는 정의되어 있지 않다고 한다. 

 

그렇다고 unlock을 해제하지 않은 상태에서 프로세스를 종료하면 이 자원에 대해서 따로 unlock하는 과정을 거쳐줘야한다고 나와있다. 

잘 모르겠다.

우선 unlock이 중복되더라도 최대 2번 밖에 중복되지 않으므로 가장 마지막에 자원을 해제하기 전에 포크를 다시 unlock하도록 했더니 오류가 난다. 하지만 모든 mutex가 unlock되었는지 신경쓰지 않고 destroy하면 잘 끝난다. (보기에는)

 

이런 고민에 대해서 인터넷을 찾아도 해결할 수 없어서 그냥 놔뒀다가 평가(동료학습)으로 해결하기로 했다. 

 

 

 

 

# 철학자가 100명대 일 때 

다른 분들은 철학자가 200, 198 등등일 때도 잘 살아계신다고 하는데 나는 1초만에 죽는다 최적화를 모르겠다. 아무리 봐도 무르겠다. 이것도 동료학습의 힘을 빌려야겠다. 나...블랙홀 늘릴 수 있을까.....  제발 살려줘.////ㅣ,,,,,,

 

 

  • 테스트 할 때 철학자의 수가 짝수일때는 time to die를 time to eat의 2배이상, 홀수일때는 3배이상의 줘야 철학자가 죽지 않습니다.

 

 

 

 

 

 

 

 

 

 

'42seoul > circle-3' 카테고리의 다른 글

[ minishell ] 1. 사전지식  (0) 2022.05.15
[minishell] 0. 과제 이해하기  (0) 2022.05.13
[Philosophers] 0. 과제 이해하기  (2) 2022.04.27

댓글