본문 바로가기
CS

[운영체제] 스레드와 멀티 스레드

by 벨롭 2023. 10. 13.

 

스레드의 의미

 

 

 

예를 들어 게임에서 점프를 할 때 동시에 호잇! 하는 효과음을 낸다고 생각해보자.

 

프로세스의 진행 흐름이 한 가지라면 점프 코드를 실행한 다음에 효과음을 내고, 그 간격을 최소화하여 인지하지 못하도록 해야할 것이다. 그런데 점프 코드를 실행하는데 걸리는 시간이 10초라면? 10초 뒤에나 효과음이 나는 요상한 상황이 된다.

 

하지만 프로세스의 진행 흐름이 여러 개라면 흐름 하나는 게임 상에 점프를 구현하고, 다른 흐름 하나는 효과음을 내도록 해 두 가지 일을 동시에 처리할 수가 있게 된다. 이 각각의 실행 흐름을 스레드라고 한다.

 

 

* 만약 프로세스라는 표현이 낯설다면, 하단의 글을 참고하자.

2023.10.13 - [CS] - [운영체제] 프로세스의 구조와 컨텍스트 스위칭

 

 

 

 

 

 

 

 

 

 

멀티 프로세스와 멀티 스레드

 

"Hello, World"라는 문장을 출력하는 간단한 프로그램이 있다고 해보자. 이 프로그램을 이용해 화면에 "Hello, World"를 세 번 출력시키려고 한다. 

 

첫 번째는, 이 프로세스를 복사해 자식 프로세스를 만들어(fork) 실행하는 멀티 프로세스 방법을 활용해볼 수 있다. 두 번째로는 프로세스 하나에 스레드를 세 개 만들어서 실행하는 멀티 스레드 방법이다. 두 가지 다 우리가 원하는 결과를 가질 수 있다. 그렇다면 차이는 무엇일까?

 

멀티 프로세스를 위해 프로세스를 fork하면 PID와 저장된 메모리 주소를 제외한 부모 프로세스의 자원들이 그대로 상속된다. 즉 부모 프로세스와 자식 프로세스는 개별적인 메모리 공간을 사용해야만 하며, 서로 독립적으로 실행된다. 만약 프로그램을 똑같이 실행하려는데 멀티 프로세스를 이용한다면 동일한 내용이 중복해서 존재해야하기 때문에 메모리에 낭비가 발생한다고 봐야한다. 또한, 서로 자원을 공유하지 않기 때문에 프로세스간의 통신을 위한 별도의 방법(IPC)가 필요하다.

 

하지만 스레드의 특징은 실행에 필요한 최소한의 정보(프로그램 카운터를 포함한 레지스터, 스택)만을 가지고 있으며 나머지 자원은 프로세스의 자원을 공유한다는 점이다. 따라서 멀티 스레드의 경우 불필요한 메모리의 중복을 방지할 수 있으며, 자원을 공유하므로 통신에 유리하다.

 

 

 

 

 

 

 

멀티 스레드의 단점

 

 

멀티 스레드에도 장점만이 있는 것은 아니다. 멀티 스레드의 경우, 하나의 스레드에 문제가 생기면 해당 스레드를 가지고 있는 프로세스 전체에 영향을 준다. 하지만 멀티 프로세스의 경우 독립적으로 존재하기 때문에 하나의 프로세스에 문제가 생기더라도 다른 프로세스는 정상적으로 작동하게 된다.

 

 

 

 

 

또한. 자원을 공유하기 때문에 동시에 스레드가 진행될 때 예기치못한 문제가 발생할 수도 있다. 

 

 

 

99만원을 가지고 있는 은행에 동시에 100명의 사람들이 와서 1만원씩을 인출해간다고 가정해보자. 사람들이 인출할 때 은행의 잔고는 99만원이므로, 1만원을 인출해주는 것은 무리없이 실행될 것이다. 하지만 100명의 사람이 빠져나가고 나니 은행의 잔고는 -1만원이 된다. (예시일 뿐, 프로그래밍적 관점에서는 다른 결과가 나온다.)

 

물론 프로세스의 경우에도 이와 같은 동기화의 문제가 발생하지만, 프로세스의 자원을 공유하는 스레드의 경우 특히나 스레드의 수행 시기를 조정해 의도대로 프로그램이 실행되도록 하는 것이(동기화) 더더욱 중요하다. 하단의 동기화 기법은 멀티 프로세스에도 동일하게 적용될 수 있으나, 설명의 편의를 위해 스레드로 용어를 통일하여 설명하고자 한다.

 

 

 

 

 

 

 

동기화 기법

 

 

공동으로 이용하는 변수, 파일, 장치 등을 공유 자원이라고 하는데, 이 공유 자원에 접근하는 코드 중 동시에 실행하면 문제가 발생하는 코드 영역을 임계 구역이라고 한다. 이 임계 구역은 여러 개의 스레드가 동시에 실행하면 문제가 되기 때문에, 문제 해결을 위해서는 스레드가 하나씩 접근하도록 해야할 것이다. 이것이 바로 상호배제(mutual exclusion, Mutex lock)이다.

 

 

 

하나의 스레드가 임계 구역에 진입할 때, 다른 스레드는 접근할 수 없도록 잠궈버린다. 그리고 임계 구역내의 모든 코드를 실행하면 잠금을 해제한다. 그러면 그제서야 다음 스레드가 임계 구역에 진입할 수 있게 된다.

 

 

하지만 이 방법도 문제가 있다. 만약 공유 자원이 여러 개 있는 임계 구역이 있을 때, 무작정 하나의 스레드가 진입했다고 잠궈버리면 대기 시간이 지나치게 길어질 수 있다. 그래서 세마포(semaphore)의 경우 임계 구역에 진입할 수 있는 스레드의 갯수를 프로그래머 임의로 지정할 수 있다. 

 

 

 

멀티 프로세스와 멀티 스레드는 프로그램의 효율성을 높여주는 유용한 방법이지만, 동기화가 제대로 진행되지 않는다면 버그가 발생하기 쉽기 때문에 이와 같은 동기화 기법을 적절히 사용하는 것이 중요하다.