[운영체제] 쓰레드 이슈

Seokjun Moon·2023년 4월 10일
0

운영체제

목록 보기
15/23
post-custom-banner

Semantics of fork() and exec()

Multi-Threaded application의 한 쓰레드가

  • fork() 를 호출하면 새로운 프로세스는 모든 쓰레드를 복제해야 할까요?!?! fork()는 호출한 쓰레드만 복제 ?! 아님 전부 다 ?! 유닉스는 두가지 버전이 있습니다.

  • exec() 실행 시 모든 쓰레드를 포함하여 새 프로세스로 대체해야 할까요 !?!?

일반적인 대처로는

fork() 이후 exec() 하면 exec 에서 지정한 프로그램이 모든 메모리 영역을 대체할 것이므로 호출한 쓰레드만 복제, 그렇지 않으면 모든 쓰레드를 복제합니다.




Signal Handling

Signal = 시스템 이벤트 입니다. 유닉스 시스템에서 프로세스에게 특정 이벤트가 발생했음을 알리기 위한 수단입니다. 동기식 혹은 비동기식으로 전달될 수 있습니다.

  • 동기식 : illegal memory access, divide by 0, ...
  • 비동기식 : Terminal interrupt (Ctrl+C 종료), Termination (오류), 타이머 만료, ...

시그널 핸들러 = 프로세스 시그널

시그널은 특정 이벤트로 인해 생성되고, 시그널은 프로세스에게 전달됩니다. 이 때 프로세스는 2가지 방식으로 처리할 수 있습니다.

  1. default : 프로세스 종료
  2. user-defined : 사용자가 대처

user-defined 는 default 를 override 하여 정의할 수 있습니다.




Thread cancellation

쓰레드는 일반적으로 루프 혹은 무한 루프를 돌리는 용도로 주로 사용합니다. 그런데 이걸 종료하고 싶을 때는 ?! cancellation 을 사용합니다. 캔슬은 굉장히 조심히 사용해야 합니다. 리소스를 다뤄야 하기 때문에 비동기로 진행해야 합니다.

캔슬에는 2가지 방식이 있습니다.

  • asynchronous cancellation
    해당 메모리를 즉시 해제합니다. 이 경우에는 shared resource problem 이 발생합니다.
  • Deferred cancellation
    타겟 쓰레드가 주기적으로 종료 여부를 스스로 체크한 후 종료가 결정되면 종료 이전에 자원을 반납합니다.

참고

  • shared resource problem : 공용 변수에 접근 시에는 해당 변수에 락을 걸어서 내가 접근 중이라는 것을 알리고 해당 변수에 다른 요청이 들어오면 대기하고 있습니다. 그 후 내가 작업을 마쳐 락을 풀면 다음 요청을 처리하는 방식입니다.
    하지만 락을 풀지 않고 종료된다면?! 다른 쓰레드는 해당 변수를 사용하지 못하는 문제가 발생합니다. 이러한 문제를 shared resource problem 이라고 합니다.
  • 이 외에도 비동기식 처리를 할 경우에는, 취소된 쓰레드로부터 시스템 자원의 일부를 회수하지 못하는 경우도 발생할 수 있습니다.

Thread cancellation status

쓰레드 취소를 호출하면, 취소가 요청되지만 실제로 취소는 쓰레드 상태에 따라 달라집니다.

쓰레드의 취소가 disabled 된 경우, 쓰레드가 취소를 enable할 때까지 취소가 pending 상태로 유지됩니다.

Default Type

기본적으로 deffered가 기본 상태입니다. 쓰레드 캔슬은 cancellation point 에 도달했을 때에만 발생합니다.

  • 예를 들어, pthread_testcancel()
  • 이후 cleanup handler 가 실행됩니다.
  • 리눅스 시스템에서는, signal을 통해 캔슬이 다뤄집니다.

Cancellation in JAVA

interrupt() 메소드를 사용합니다.

while (!Thread.currentThread().isInterrupted()) {}




Thread-Local Storage (TLS)

쓰레드의 고유한 전역/정적 변수를 사용할 수 있게 해줍니다. 쓰레드들 사이 공유가 가능합니다. 약간 static data 와 비슷한 느낌입니다. 다른 점이라면, TLS는 각 쓰레드에서 유니크하게 존재합니다. 쓰레드 생성 프로세스를 제어할 수 없을 때 유용하게 쓰이는 방식입니다. (예를 들어 쓰레드 풀 사용 시에)




Scheduler Activations

앞서 Multi-Threading Model 에서 M:M 그리고 Two-level Model 에서는 유저-쓰레드와 커널-쓰레드의 개수가 1:1 매핑이 아니므로 application에게 할당된 kernel threads를 적정 개수로 유지하기 위해 통신을 요구합니다. 이러한 통신은 어플리케이션이 커널 쓰레드의 개수를 알맞게 유지할 수 있도록 해줍니다.

따라서 보통 유저 쓰레드와 커널 쓰레드 사이에 intermediate data structure을 둬서 사용합니다. 이를 스케쥴 하기 위한 가상의 프로세스를 하나 두는데, 이를 Lightweight Process (LWP) 라고 합니다. LWP는 커널 쓰레드에 1:1 매핑됩니다.

  • 그렇다면, 4개의 I/O를 동시에 수행하는 경우에 필요한 LWP의 개수는?? (아마도 4개)

upcall

upcall은 커널이 특정 이벤트에 대해 어플리케이션에 알리는 프로세스를 말합니다. scheduler activation은 upcall을 생성합니다. 커널은 어플리케이션에게 LWP Set (1개 이상의 LWP)을 제공합니다. 어플리케이션은 사용자 쓰레드를 available virtual processor (LWP)로 예약 가능합니다.

upcall은 쓰레드 라이브러리에서 upcall handler를 통해 처리되며, 이는 LWP에서 실행되어야 합니다. 이러한 통신으로 어플리케이션이 적정 수의 커널 쓰레드를 유지할 수 있도록 해줍니다.

profile
차근차근 천천히
post-custom-banner

0개의 댓글