Threading Issues (스레드와 관련된 문제)

이찬영·2021년 8월 4일
0

OS

목록 보기
7/35

Fork() 및 Exec() 시스템 콜

다중 스레드 프로그램에서는 fork()와 exec()의 의미가 달라질 수 있다.
fork 호출시 새로운 프로세스는 모든 스레드를 복제해야하는가? 아니면 한개의 스레드만 복제해야하는가? fork()는 이 두가지 복제방법을 모두 제공한다.

exec() 시스템콜을 부르면 exec()의 매개변수로 지정된 프로그램이 모든 스레드를 포함한 전체 프로세스를 대체시킨다.

두 버전의 fork() 중 선택은 프로그램에 달렸다. fork() 호출이후 바로 exec()를 호출한다면 모든 스레드를 다 복제할 필요가 없을 것이다. 하지만 fork() 호출 이후 exec()를 호출하지 않는다면 새 프로세스는 모든 스레드를 복제해야한다.

Signal Handling (신호 처리)

Signal은 Unix에서 프로세스에 어떤 이벤트가 일어났음을 알려주기 위해 사용 된다.

Signal의 전달 방식

  1. Signal은 특정 이벤트가 일어나야 생성
  2. 생성된 Signal가 프로세스에 전달
  3. 신호가 전달되면 반드시 처리

Signal의 종류

동기식 Signal

불법적인 메모리 접근, 0으로 나누기 등 실행 중인 프로그램이 부적절한 행동시 신호가 발생한다.

비동기식 Signal

실행 중인 프로세스 외부로 부터 발생하면 프로세스 신호를 비동기식으로 전달 받는다.
예를 들어 control+c와 같은 강제 종료 키나 타이머가 만료되는 경우 등이 있다.

Signal Handler 종류

  1. Default Signal Handler
    Default Signal Handler가 처리하는 신호를 User-Defined Signal Handler로 대체할 수 있다.

  2. User-Defined Signal Handler

다중 스레드 환경에서의 Signal 전달 문제

  1. Signal가 적용될 스레드에게 전달한다.
  2. 모든 스레드에 전달한다.
  3. 몇몇 스레드에 선택적으로 전달한다.
  4. 특정 스레드가 모든 신호를 전달 받도록 지정한다.

Signal을 전달하는 방법은 신호의 유형에 따라 다르다.
예를 들어 동기식 신호는 신호를 야기한 스레드에 전달 되어야하며 다른 스레드에게는 전달되면 안된다.
비동기식 신호는 (control+c와 같은) 모든 스레드에 전달되어야하며 어떠한 신호는 특정 스레드에만 전달 되어야 한다.

모든 스레드에게 전달 되어야할때는 Unix에서 신호를 절달하는 함수는 kill(ptd_t pid, int signal) 를 사용한다.

특정 프로세스를 지정한 후 Signal을 보낸다. 특정 스레드에게 전달 해야할때는 pthread_kill(pthread_t tid, int signal)를 사용한다.

Thread Cancellation (스레드 취소)

스레드 취소란 스레드가 끝나기 전에 그것을 강제 종료 시키는 작업이다.
예를 들어 여러 스레드가 데이터베이스를 병렬로 검색하고 있다가 한 스레드가 결과를 찾으면 나머지 스레드는 취소되어도 된다.

이 처럼 취소되어야할 스레드를 traget thread(목적 스레드)라고 부른다. 목적 스레드의 취소는 두가지 방식으로 발생한다.

  1. Asynchronous cancellation (비동기식 취소)
    한 스레드가 즉시 목적 스레드를 강제 종료 시킨다.
  2. Deferred Cancellation (지연 취소)
    목적 스레드가 주기적으로 자신이 강제 종료 될어야할지 확인한다. 목적 스레드가 순서에 맞게 종료될 수 있도록 할 수 있다.

스레드 취소는 할당된 자원으로 인해 문제가 발생한다. 스레드가 다른 스레드와 공유하는 자료구조를 갱신하는 도중에 취소 요청이 오면 문제가 발생한다.
이 문제는 비동기식 취소에서 더 심각한 문제를 일으킨다. OS는 취소된 스레드로 부터 자원을 회수할 수도 있지만, 모든 시스템 자원을 다 회수하지 못하는 경우도 있다. 따라서 비동기식으로 스레드를 취소하면 필요한 시스템 자원을 다시 사용 가능한 상태로 만들지 못할 수 도 있다.
지연 취소의 경우 한 스레드가 목적 스레드를 취소해야 한다고 표시하지만 실제 취소는 목적 스레드가 취소 여부를 결정하는 플래그를 검사한 이후에 발생한다.

pThread와 Java는 지연 취소를 권장하고 있다.

Thread-Local Storage

스레드는 자신만 엑섹스할 수 있는 데이터를 가져올 필요가 있다. 이러한 데이터를 thread-local storage (TLS) 라고 한다. TLS는 지역변수와 혼동하기 쉽다. 지역변수는 하나의 함수가 호출되는 동안 존재하지만 TLS는 스레드 전체 함수 호출에 걸쳐 존재한다. Implicit Threading을 사용하는 경우는 TLS가 아닌 다른 방법이 필요하다.

Scheduler Activations

스레드 라이브러리와 커널의 통신 문제를 고려해야한다. 이 통신은 Many to Many 또는 Two Level 모델에서 해결해야할 문제이다. 이러한 문제를 해결하기 위해 커널 스레드의 수를 동적으로 조절하는것을 가능하게 한다.

LWP

Many to Many 또는 Two Level 모델을 구현하는 많은 시스템은 커널 스레드 사이에 중간 자료구조를 둔다. 이 자료구조는 LWP (경량 프로세스)라 불린다.

LWP는 커널 스레드와 유저스레드를 연결하는 자료구조이다. LWP는 유저레벨에 존재하는 스레드. LWP는 커널 스레드 수만큼 존재한다. 커널은 프로그램에게 유저 스레드를 연결하고 취소하는 이벤트를 발생하는데 이것을 upcall이라고 한다.

LWP의 좀더 자세한 내용은 아래의 블로그를 참조
https://byounghoonkim.github.io/posts/2019-03-07-the_linux_implementation_of_threads/
https://m.blog.naver.com/PostView.nhn?blogId=x21999&logNo=220767565982&proxyReferer=https:%2F%2Fwww.google.com%2F

Scheduler Activations 방법

스케쥴 엑티베이션은 어떤식으로 멀티플렉싱을 할것이냐를 의미한다. 커널은 프로그램에 LWP의 집합을 제공하고 프로그램은 사용자 스레드를 가용한 LWP로 스케줄 한다. 프로그램 내 스레드가 시스템 콜과 같은 이유로 블락킹 될때 커널은 upcall 이벤트를 발생하여 블락킹 된다는 사실을 알린 후 LWP와 연결된 스레드는 블락이 된다. LWP가 블락되기 전에 LWP와 연결된 스레드 중 블락킹 될 스레드를 제외한 사용 가능한 스레드는 블락 되지 않은 LWP로 옮겨 준다. 커널에서 완료 이벤트를 발생하면 커널은 이전에 블락 된 LWP가 다시 사용할 수 있다는 upcall 이벤트를 발생한다. 이벤트를 확인한 LWP는 다시 사용가능 하도록 블락이 해제 된다.

결과적으로 간단하게 말하면 커널과 LWP간 통신으로 프로그램의 스레드를 스케쥴링하는 것이다.

0개의 댓글