스레드에 대해서 알아보자

SeokHwan An·2025년 1월 9일
0

운영체제 스터디

목록 보기
4/7

지난 포스트에서 프로세스에 대해서 알아보았습니다. 프로세스의 특징은 독립적인 메모리 공간을 가지고 있어서 멀티 프로세스 환경에서는 서로 영향을 미치지 않아서 안정성이 높은 반면 새로운 프로세스를 생성하는 것과 프로세스의 문맥전환 과정에서 많은 오버헤드가 발생한다는 특징이 있습니다. 이와 같은 문제를 해결하고자 프로세스보다 작은 단위의 실행 수단을 프로세스 내에서 만들어 한 프로세스에서 각각 별도의 진행 플로우를 만들자는 아이디어가 나왔고 그의 결과물이 스레드의 등장입니다.

스레드란?

스레드는 프로세스 내에서 실행되는 흐름의 단위를 의미합니다. 프로세스 내에는 적어도 한개의 스레드가 존재하며 한 프로세스 내 여러 쓰레드는 메모리를 공유해 나가며 작업을 수행합니다. 간단하게 예를 들면 유튜브에 여러 요청이 발생했을 때를 보겠습니다.

여러 사용자가 동영상 재생 요청을 보내게 되면 유튜브 내부에서는 여러 쓰레드가 독자적으로 각 요청에 대한 처리를 진행합니다.

스레드의 메모리 구조

스레드는 프로세스 내에서 스택 영역만 할당 받고 힙, 데이터, 코드 영역을 서로 공유해서 이용합니다. 힙영역을 공유해서 사용하기 있기에 스레드간의 협력은 프로세스간의 협력에 비해 비교적 간단하게 진행됩니다. 하지만 힙 영역의 데이터를 공유해서 이용하다보니 여러 스레드가 동시에 동작하는 과정에서 race condition 문제와 데드락이 발생할 수 있습니다.

💡 왜 스택 영역만 독자적으로 가지는 것일까?
스택 영역은 함수 호출 시 매개 변수, 지역 변수가 저장되는 영역입니다. 해당 영역을 각각 가진다는 것은 스레드마다 독립적으로 함수 호출이 가능하다는 것을 의미하고 이는 여러 스레드가 같이 동작하는 것이 아닌 독립적인 실행 흐름을 가질 수 있다는 것을 의미합니다.

스레드 제어블록

스레드는 프로세스 내에서 생성 및 동작하기 있기에 프로세스 제어블록 내에서 스레드 제어블록을 참조해 운영체제가 스레드 제어블록을 관리할 수 있게 합니다.

요소설명
스레드 ID (TID)각 스레드를 구분하기 위한 고유한 식별자. 프로세스 내에서 각 스레드를 식별하는 데 사용됩니다.
상태 (State)스레드의 현재 상태를 나타냅니다. 예: Running, Ready, Blocked 등.
프로그램 카운터 (PC)현재 실행 중인 명령어의 주소를 저장합니다. 스레드가 중단되었다가 재개될 때 실행 위치를 추적합니다.
스택 포인터 (SP)스레드의 스택이 위치하는 메모리 주소를 가리킵니다. 각 스레드는 독립적인 스택을 가집니다.
레지스터 값스레드가 실행 중일 때 사용하는 CPU 레지스터의 값을 저장합니다. 각 스레드마다 독립적인 레지스터 세트가 필요합니다.
우선순위 (Priority)스레드의 실행 우선순위를 나타냅니다. 스케줄링을 할 때 우선순위에 따라 실행 순서가 결정됩니다.
소속 프로세스 정보해당 스레드가 속한 프로세스에 대한 정보입니다. 보통 PCB(프로세스 제어 블록)를 참조합니다.

스레드 종류

스레드는 크게 사용자 스레드(User Level Thread)커널 스레드(Kernel Level Thread)로 나눌 수 있습니다.

사용자 스레드는 프로그래밍 언어 내에서 라이브러리를 통해 구현된 스레드를 의미합니다. 커널의 지원 없이 사용자 영역에서 스레드의 생성과 관리가 이루어집니다. 커널은 해당 프로세스만 인식할 뿐 스레드를 인식하지 못하며 그로인해 스레드간 문맥 교환과정에서 커널 모드의 전환이 필요없기에 성능상의 이점이 있습니다. 하지만 해당 프로세스가 특정 상황(I/O 등)등으로 인해서 block이 되면 내부 모든 스레드 작업들이 모두 멈추는 문제가 발생합니다.

반면 커널 스레드는 운영체제가 직접 관리하며, 커널이 스케줄링의 대상으로 인식하고 관리합니다. 이를 통해 스레드 단위로 작업을 스케쥴링할 수 있다는 점과 멀티 프로세서에서 여러 스레드를 병렬로 처리가 가능합니다. 하지만 스레드간의 스케쥴링을 통해서 문맥교환이 발생하고 이로인해 오버헤드가 발생할 수 있습니다.

CPU에서는 커널 스레드가 동작되기에 CPU에 사용자 스레드가 할당되고 스케줄링이 되기 위해서는 사용자 스레드와 커널 스레드가 반드시 연결이 되어야 합니다. 사용자 스레드와 커널 스레드의 연결 방식에 대해서 알아보겠습니다.

✏️ one-to-one model

  • 사용자 스레드와 커널 스레드가 1대1로 매핑되는 방식
  • 스레드 관리를 운영체제에게 위임(스케쥴링 등)
  • 하나의 사용자 스레드에서 i/O가 발생하더라도 다른 스레드들은 동작이 가능
  • race condition이 발생할 수 있음

✏️ many-to-one model

  • 커널 스레드 1개에 여러 사용자 스레드가 매핑되는 방식
  • one-to-one 방식에 비해 문맥 교환이 빠름(사용자 레벨에서만 스레드 교환 발생)
  • one-to-one 방식에 비해 상대적으로 race condition이 발생할 가능성이 적음
  • 멀티 코어 활용이 어려움
  • 하나의 사용자 스레드에서 I/O가 발생해 이와 연결된 커널 스레드가 block이 되면 나머지 사용자 스레드도 동작이 불가능

✏️ many-to-many model

  • n개에 커널 스레드와 m개의 사용자 스레드가 매핑되는 방식
  • ono-to-one 방식과 many-to-one 방식의 장점을 모은 방식
  • 하나의 사용자 스레드가 i/o를 하더라도 다른 사용자 스레드는 동작가능하며 사용자 스레드 간의 문맥 교환이 일어나 오버헤드가 작음

멀티 프로세스 VS 멀티 쓰레드

이번에는 멀티 프로세스와 멀티 쓰레드의 특징을 비교해보도록 하겠습니다. 두 방식 모두 병렬 처리를 위한 방법이지만, 각각의 장단점이 있어 상황에 따라 적절한 선택이 필요합니다.

비교 기준멀티 프로세스멀티 쓰레드
메모리 사용각 프로세스마다 독립적인 메모리 영역 필요스레드간 메모리 공유로 효율적
통신 방식IPC를 통한 통신 필요공유 메모리를 통한 간단한 통신
안정성하나의 프로세스가 죽어도 다른 프로세스에 영향 없음하나의 스레드 문제가 전체 프로세스에 영향

멀티 프로세스와 멀티 스레드의 차이를 살펴보면, 멀티 프로세스는 안정성이 높지만 메모리 사용량이 많고 프로세스 간 통신이 복잡한 반면, 멀티 스레드는 메모리를 효율적으로 사용하고 통신이 간단하지만 안정성이 상대적으로 낮다는 특징이 있습니다. 따라서 시스템의 요구사항과 특성에 따라 적절한 방식을 선택하는 것이 중요합니다.

이러한 특성들을 고려할 때, 웹 서버와 같이 많은 클라이언트 요청을 처리해야 하는 서비스에서는 멀티 스레드 방식이 자주 사용됩니다. 반면, 하나의 작업이 실패해도 다른 작업에 영향을 주지 않아야 하는 중요한 시스템에서는 멀티 프로세스 방식이 선호됩니다. 실제 많은 현대 시스템들은 두 방식을 혼합하여 사용함으로써 각각의 장점을 최대한 활용하고 있습니다.

멀티 쓰레드의 주의할점

멀티 쓰레드를 사용할 때는 여러 가지 주의해야 할 점들이 있습니다. 가장 중요한 것은 여러 스레드가 공유 자원에 동시에 접근할 때 발생할 수 있는 동기화 문제입니다. 이러한 문제를 해결하기 위해 뮤텍스(Mutex)나 세마포어(Semaphore)와 같은 동기화 메커니즘을 적절히 사용해야 합니다.

또한 데드락(Deadlock) 상황을 방지하기 위해 자원 할당 순서를 일관되게 유지하고, 적절한 타임아웃을 설정하는 것이 중요합니다. 스레드 풀(Thread Pool)을 사용하여 스레드의 생성과 소멸에 따른 오버헤드를 줄이는 것도 효율적인 멀티스레드 프로그래밍을 위한 좋은 방법입니다.

정리

  • 스레드는 프로세스의 실행단위를 의미합니다.
  • 스레드는 독립적인 스택영역을 제외하고 힙, 데이터, 코드 영역은 공유해서 사용합니다.
  • 스레드 제어블록을 통해서 운영체제가 스레드를 관리할 수 있습니다.
  • 스레드는 크게 사용자 스레드와, 커널 스레드로 구분되며 사용자 스레드는 라이브러리를 통해 사용자가 생성한 스레드이고 커널 스레드는 OS가 활용하는 스레드 입니다.
  • 멀티 스레드를 이용하는 것은 멀티 프로세스에 비해서 문맥 교환시 오버헤드가 적고 메모리를 효율적으로 사용할 수 있지만 공유 메모리의 데이터를 다룰 때에는 데드락과 race condition 문제거 발생할 수 있습니다.

0개의 댓글