{{위키데이터 속성 추적}}
{{다른 뜻|스레드 플로트형 게시판||[[전자 게시판]]의 종류}}
[[파일:Multithreaded process.svg|섬네일|두 개의 스레드를 실행하고 있는 하나의 프로세스.]]
'''스레드'''(thread)는 어떠한 프로그램 내에서, 특히 [[프로세스]] 내에서 실행되는 흐름의 단위를 말한다. 일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을 [[멀티스레딩|멀티스레드]](multithread)라고 한다.

== 프로세스와 스레드의 비교 ==
멀티프로세스와 멀티스레드는 양쪽 모두 여러 흐름이 동시에 진행된다는 공통점을 가지고 있다. 하지만 멀티프로세스에서 각 프로세스는 독립적으로 실행되며 각각 별개의 메모리를 차지하고 있는 것과 달리 멀티스레드는 프로세스 내의 메모리를 공유해 사용할 수 있다. 또한 프로세스 간의 전환 속도보다 스레드 간의 전환 속도가 빠르다.

멀티스레드의 다른 장점은 CPU가 여러 개일 경우에 각각의 CPU가 스레드 하나씩을 담당하는 방법으로 속도를 높일 수 있다는 것이다. 이러한 시스템에서는 여러 스레드가 실제 시간상으로 동시에 수행될 수 있기 때문이다.

멀티스레드의 단점에는 각각의 스레드 중 어떤 것이 먼저 실행될지 그 순서를 알 수 없다는 것이 있다. 예를 들어, 두 스레드가 특정 공유 변수 i의 값을 1 증가시키는 명령을 실행할 때, 다음과 같은 방식으로 수행될 수 있다.
# 공유되는 변수 i의 값을 [[프로세서 레지스터|레지스터]]에 저장
# 레지스터의 값을 1 증가시킨다.
# 변수 i에 그 값을 저장한다.

이때 두 스레드가 실행될 때 어떤 스레드가 먼저 실행될지는 보장되지 않으며, 만약 다음과 같은 순서로 실행된다면:
{| class="wikitable"
|-
! 스레드 !! 동작 !! i의 값 !! 스레드 1의 레지스터 !! 스레드 2의 레지스터
|-
| 스레드 1 || i의 값을 레지스터에 저장 || 0 || 0 ||
|-
| 스레드 1 || 레지스터 값을 1 증가 || 0 || 1 ||
|-
| 스레드 1 || i에 값 저장 || '''1''' || 1 ||
|-
| 스레드 2 || i의 값을 레지스터에 저장 || 1 || 1 || 1
|-
| 스레드 2 || 레지스터 값을 1 증가 || 1 || 1 || 2
|-
| 스레드 2 || i에 값 저장 || '''2''' || 1 || 2
|}
최종 결과로 i는 2가 증가된다. 하지만 다음과 같이 실행된다면:
{| class="wikitable"
|-
! 스레드 !! 동작 !! i의 값 !! 스레드 1의 레지스터 !! 스레드 2의 레지스터
|-
| 스레드 1 || i의 값을 레지스터에 저장 || 0 || 0 ||
|-
| 스레드 2 || i의 값을 레지스터에 저장 || 0 || 0 || 0
|-
| 스레드 1 || 레지스터 값을 1 증가 || 0 || 1 || 0
|-
| 스레드 2 || 레지스터 값을 1 증가 || 0 || 1 || 1
|-
| 스레드 1 || i에 값 저장 || '''1''' || 1 || 1
|-
| 스레드 2 || i에 값 저장 || '''1''' || 1 || 1
|}
최종 결과로 i는 1이 증가되고, 이것은 원래 프로그램의 의도(각각의 스레드가 i를 1씩 증가하는 동작)와 다를 수 있다. 또한 이러한 문제는 스레드의 실행 조건에 따라 결과가 다르게 나오므로, 오류가 발생했을 때 원인을 찾기가 힘들다. 이러한 문제를 [[경쟁 조건]]이라고 하며, 문제를 막기 위해 [[세마포어]]와 같은 방법을 통해 공유 데이터에 접근하는 스레드의 개수를 한개 이하로 유지하는 방법을 사용할 수 있다.

== 스레드의 종류 ==
스레드를 지원하는 주체에 따라 2가지로 나눌 수 있다.

=== 사용자 레벨 스레드 (User-Level Thread) ===
사용자 스레드는 커널 영역의 상위에서 지원되며 일반적으로 사용자 레벨의 라이브러리를 통해 구현되며, 라이브러리는 스레드의 생성 및 스케줄링 등에 관한 관리 기능을 제공한다. 동일한 메모리 영역에서 스레드가 생성 및 관리되므로 속도가 빠른 장점이 있는 반면, 여러 개의 사용자 스레드 중 하나의 스레드가 시스템 호출 등으로 중단되면 나머지 모든 스레드 역시 중단되는 단점이 있다. 이는 커널이 프로세스 내부의 스레드를 인식하지 못하며 해당 프로세스를 대기 상태로 전환시키기 때문이다.

=== 커널 레벨 스레드 (Kernel-Level Thread) ===
[[커널 (컴퓨팅)|커널]] 스레드는 운영체제가 지원하는 스레드 기능으로 구현되며, 커널이 스레드의 생성 및 스케줄링 등을 관리한다. 스레드가 시스템 호출 등으로 중단되더라도, 커널은 프로세스 내의 다른 스레드를 중단시키지 않고 계속 실행시켜준다. [[다중처리기]] 환경에서 커널은 여러 개의 스레드를 각각 다른 처리기에 할당할 수 있다. 다만, 사용자 스레드에 비해 생성 및 관리하는 것이 느리다.

== 스레드 데이터 ==
=== 스레드 기본 데이터 ===
스레드도 프로세스와 마찬가지로 하나의 실행 흐름이므로 실행과 관련된 데이터가 필요하다. 일반적으로 스레드는 자신만의 고유한 스레드 ID, 프로그램 카운터, 레지스터 집합, 스택을 가진다. 코드, 데이터, 파일 등 기타 자원은 프로세스 내의 다른 스레드와 공유한다.

=== 스레드 특정 데이터 ===
위의 기본 데이터 외에도 하나의 스레드에만 연관된 데이터가 필요한 경우가 있는데, 이런 데이터를 '''스레드 특정 데이터'''(Thread-Specific Data, 줄여서 TSD)라고 한다. 멀티스레드 프로그래밍 환경에서 모든 스레드는 프로세스의 데이터를 공유하고 있지만, 특별한 경우에는 개별 스레드만의 자료 공간이 필요하다. 예를 들어 여러 개의 [[트랜잭션]]을 스레드로 처리할 경우, 각각의 트랜잭션 ID를 기억하고 있어야 하는데, 이때 TSD가 필요하다. TSD는 여러 스레드 라이브러리들이 지원하는 기능 중의 하나이다.

== 프로세스 관리의 변화 ==
멀티스레드 환경이 확산됨에 따라 전통적인 프로세스 관리 방식에도 변화가 필요해졌다. 예를 들어, [[포크 (시스템 호출)|fork]] 또는 [[exec]]와 같은 시스템 호출시에 어떻게 처리할 것인가 하는 문제가 대두된 것이다.
* fork 문제 : 어떤 프로세스 내의 스레드가 fork를 호출하면 모든 스레드를 가진 프로세스를 생성할 것인지, 아니면 fork를 요청한 스레드만 가진 프로세스를 생성할 것인지 하는 문제이다. [[유닉스]]에서는 각각 2가지 버전의 fork를 지원하고 있다.
* exec 문제 : fork를 통해 모든 스레드를 복제하고 난 후, exec를 수행한다면 모든 스레드들이 초기화된다. 그렇다면 교체될 스레드를 복제하는 작업은 필요가 없기 때문에 애초에 fork를 요청한 스레드만을 복제했어야 한다. 한편, fork를 한 후에 exec를 수행하지 않는다면 모든 스레드를 복제할 필요가 있는 경우도 있다

== 같이 보기 ==
{{위키공용분류}}
* [[멀티스레딩]]

== 외부 링크 ==
* [https://web.archive.org/web/20070110134819/http://terms.co.kr/thread.htm 스레드/멀티스레딩]

{{운영 체제}}
{{병렬 컴퓨팅}}
{{전거 통제}}

[[분류:스레드| ]]
[[분류:병행 컴퓨팅]]