Seongwon Lim

[OS] 스레드란 무엇인가? 본문

Operating System

[OS] 스레드란 무엇인가?

limsw 2022. 5. 7. 15:43
반응형

서론

최근에 파이썬으로 멀티쓰레딩을 구현하는 방법을 공부한 적이 있었는데 스레드의 개념이 머릿속에 확실히 정립되지 않았다. 작년에 운영체제 수업을 들으며 분명히 배운 기억은 나는데 시간이 지나면서 많이 까먹은 것 같다. 그래서 이번 글에서는 스레드, 멀티 스레드의 개념을 살펴보고 스레드가 가지는 특징들은 무엇이 있는지 알아보고자 한다.

스레드란 무엇일까?

스레드(thread)란 프로세스(process) 내에서 실제로 작업을 수행하는 주체로 모든 프로세스는 한 개 이상의 스레드를 가지고 있다.

 

  • 프로세스 내에서 2개 이상의 스레드를 가지고 있는 경우 해당 프로세스는 멀티 스레드를 포함하고 있다고 볼 수 있다.

 

스레드의 정의를 조금 더 쉽게 설명하자면, 스레드는 프로세스가 CPU로부터 할당받은 자원을 이용하는 실행의 단위이다.

이해를 돕고자 예시를 들면, 지금 필자가 글을 포스팅하기 위해 띄운 크롬 브라우저를 프로세스라고 가정해보자.

 

브라우저를 프로세스라고 가정한다면 스레드는 다음과 같은 것들이 포함될 수 있다.

 

  • 유튜브에서 음악 스트리밍하기, 넷플릭스 페이지에서 드라마 시청하기

 

만약에 필자가 브라우저에서 별다른 일을 하지 않고 유튜브에서 음악만 듣고 있다면 그것은 1개의 일을 하는 상태라고 볼 수 있다. 즉, 스레드가 단일 스레드(single-thread)로써 역할을 수행하고 있는 것이다.

 

그러나, 음악만 듣는 것이 아니라 드라마 보기 행위도 같이 하고 있다면 이 때에는 브라우저라는 프로세스에서는 2개의 일이 병렬적으로 수행되고 있는 것이다. 우리는 이 때를 하나의 프로세스에서 두 개의 스레드가 실행되고 있다고 말할 수 있고 이러한 개념을 멀티 쓰레드(multi-thread)라고 한다.

스레드 & 멀티 스레드 개념 정리하기

싱글(단일) 스레드

  • 하나의 프로세스 내에서 하나의 일만 처리할 수 있다.
  • 하나의 프로세스에는 한 개의 스레드가 존재한다.
  • 각 일은 순차적으로 실행된다. (이전 작업이 끝나기 전까지 다른 작업은 Waiting 상태이다.)
  • Task 1 -> Task 2 -> Task 3 과 같은 순서로 실행된다.

멀티 스레드

  • 두 가지 이상의 일을 동시에 처리하는 것을 의미한다.
  • 하나의 프로세스 내에서 두 개 이상의 스레드가 존재한다.
  • Thread A : Task 1 -> Task 2
  • Thread B : Task 3 -> Task 4 -> Task 5

스레드 구조 정리하기

위 사진에서 볼 수 있듯이 스레드는 Heap, Data, Code 영역은 공유하며 별도의 Execution stack을 가지는 구조로 구성되어 있다.

 

Code 영역

  • 프로세스가 실행할 코드가 기계어 형태로 저장된 공간. 컴파일 할 때 결정되며 중간 코드 수정이 불가능한 Read Only 형태이다.

Data 영역

  • 코드에서 선언한 정적 변수, 전역 변수 등이 저장된 공간. 변수는 수정될 수 있으므로 데이터 영역은 Read and Write 형태이다.

Heap 영역

  • 배열의 크기가 확실하지 않고 가변적일 때 Heap 영역을 이용해서 메모리를 할당할 수 있다. malloc, calloc 등의 명령어로 힙 영역에 접근할 수 있으며 사용 후에 힙 영역을 해제하지 않으면 메모리 누수 현상이 발생할 수 있다.

Stack 영역

  • 프로세스 메모리 공간 관리를 위한 알고리즘. 컴파일 타임에 크기가 결정되며 해당 영역에는 함수에 선언된 변수, 리턴값, 주소 등이 저장되며 함수는 종료시 제거된다. 스택은 LIFO(Last in First Out) 형태를 따른다.

멀티 스레드가 더 좋은 것이 아닐까?

여태까지 다룬 내용을 바탕으로 추측해보면 여러 일을 병렬적으로 처리할 수 있는 멀티 스레드가 당연히 좋은 것이 아닌가? 라고 생각할 수도 있다. 왜냐하면 멀티 스레드는 각 스레드가 자신이 속한 프로세스의 메모리를 공유하므로 시스템 자원의 낭비가 적고, 하나의 스레드가 작업을 할 때 다른 스레드가 별도의 작업을 할 수 있어 사용자와의 응답성도 좋아지기 때문이다.

 

그러나 우리가 배우는 기술은 모두 각각의 장단점이 존재한다. 때문에 무작정 멀티 스레드로 프로그램을 구현하는 방법이 항상 옳다고 말할 수 없다. 그러면 멀티 스레드를 사용할 때 고려해야 하는 상황은 무엇이 있을까?

Context Switching

문맥 교환(Context Switching)이란 현재까지의 작업 상태나 다음 작업에 필요한 각종 데이터를 저장하고 읽어오는 작업을 말한다.

스레드는 서로 교체될 때 스레드 간의 문맥 교환(context switching)이라는 것이 발생한다. Task 1 -> Task 2로 넘어가는 순간 문맥 교환이 일어나는 것이고, Task 2 -> Task 3으로 넘어갈 때에도 문맥 교환이 일어난다.

 

  • 이렇게 멀티 스레드는 빈번한 문맥 교환을 통해서 일을 조금씩 처리하는 것이다. 그러나 그 속도가 매우 빠르기 때문에 사용자 입장에서는 모든 일이 동시에 처리되는 것처럼 느끼는 것이다.

 

그러나 문맥 교환은 걸리는 시간이 커지면 커질수록 멀티 스레딩의 효율은 떨어진다.

 

예를 들어, CPU의 코어 수는 1개인데 여러 개의 스레드가 실행되면, 각 코어들은 정해진 시간 동안 여러 작업을 번갈아가며 수행한다. 이러한 경우 매우 빈번하게 문맥 교환이 일어날 것이다. 결과적으로 스레드의 문맥 교환의 오버헤드(Overhead)가 매우 커지게 되고 오히려 스레드 생성 시간이 단일 스레드보다 느려질 수 있다.

 

따라서 시스템을 설계할 때 많은 수의 스레드를 실행하는 것이 언제나 좋은 성능을 보장하는 것은 아니라는 점을 유의해야 한다.

공유 자원 문제

여러 개의 스레드는 Code, Data, Heap과 같은 자원을 공유하여 사용하기 때문에 적절한 컨트롤이 필요하다.
예를 들어, 사용자가 어떤 자원에 접근하여 해당 자원을 조작하고 있을 때, 다른 스레드가 이 자원에 접근한다면 이는 동시성(Concurrency) 문제로 인한 자원의 일관성이 깨질 수 있다.

 

우리는 이러한 동시성으로 인해 생기는 문제를 경쟁 조건(Race Condition)이라고 부르는데 이 글에서는 경쟁 조건은 다루지 않기로 했다.

따라서 다중 스레드가 접근하는 공유 자원에 대해서는 동기화 작업이 필요하다.


출처

Comments