운영체제로부터 자원을 할당받는 작업의 단위, 실행 중인 프로그램
<독립적인 프로세스>
<메모리상의 프로세스>
프로세스가 할당받은 자원을 이용하는 실행의 단위
스레드는 프로세스 내에서 각각의 스택 공간을 제외한 나머지 공간과 시스템 자원을 공유한다.그러므로 프로세스를 이용하여 동시에 처리하던 일을 스레드로 구현할 경우 메모리 공간은 물론 시스템 자원 소모도 현격히 줄어들게 된다. 하나의 프로세스에서 여러 스레드가 존재하게 되니 스레드 간의 통신이 필요한 경우 별도의 자원을 이용하는 것이 아니라 메모리 공간을 공유하므로 데이터 세그먼트, 즉 전역 변수를 이용하여 구현한다. 그런데 공유하는 전역 변수를 여러 스레드가 함께 사용하게되면 충돌이 발생하게된다. 따라서 스레드 간에 통신할 경우에는 충돌 문제가 발생하지 않도록 동기화 문제를 해결해야 한다.
<프로세스 내의 스레드>
스택은 함수 호출 시 전달되는 인자, 되돌아갈 주소값 및 함수 내에서 선언하는 변수 등을 저장하기 위해 사용되는 메모리 공간이므로 스택 메모리 공간이 독립적이라는 것은 독립적인 함수 호출이 가능하다는 것이고 이는 독립적인 실행 흐름이 추가되는 것이다. 따라서 스레드의 정의에 따라 독립적인 실행 흐름을 추가하기 위한 최소 조건으로 독립된 스택을 할당한다.
PC 값은 스레드가 명령어의 어디까지 수행하였는지를 나타나게 된다. 스레드는 CPU 를 할당받았다가 스케줄러에 의해 다시 선점당한다. 그렇기 때문에 명령어가 연속적으로 수행되지 못하고 어느 부분까지 수행했는지 기억할 필요가 있다. 따라서 PC 레지스터를 독립적으로 할당한다.
운영체제는 시스템 작업을 효율적으로 관리하기 위해 스레드를 이용한다.
즉, 멀티 프로세스로 실행되는 작업을 멀티 스레드로 실행하게 되면 프로세스를 생성하여 자원을 할당하는 과정도 줄어들 뿐더러 프로세스를 컨텍스트 스위칭(Context Switching)하는 것 보다 오버헤드를 더 줄일 수 있게 된다. 뿐만 아니라 프로세스간의 통신 비용보다 하나의 프로세스 내에서 여러 스레드간의 통신 비용이 훨씬 적으므로 작업들 간의 통신 부담을 줄일 수 있게 된다.
예를들어보자. 구글 docs를 이용하여 어떤 문서를 함께 작성해야한다.
이때 하나의 구글 docs를 프로세스라 생각하고 문서에 참여하는 사용자를 스레드라 생각해보자.
만약 멀티 프로세스라면 사용자 한명당 하나의 구글 docs를 켜서 자신이 해야하는 임무를 마무리 하고 도출된 결과를 합쳐야 할 것이고
멀티 스레드라면 하나의 구글 docs에서 여러 사람들이 분배받은 커서를 이용하여 자신의 임무를 마무리 하면 된다.
위 예시를 살펴보면 여러 구글 docs가 아닌 하나의 구글 docs를 만들었기에 자원 할당에서도 유리한 모습을 보였고, 모든 구글 docs를 하나의 구글 docs로 합치는 것을 통신 비용이라 생각한다면 하나의 구글 docs에서 여러 사용자들이 함께 임무를 수행하는게 더 효율적이라고 쉽게 생각 할 수 있다.
자식 프로세스가 생성되고 난 다음에는 부모프로세스가 가진 핸들테이블은 상속되지만 모든것(Code/data/heap/stack영역) 이 독립적으로 만들어진다. 이러한 메모리 구조를 지녔기에, 프로세스간에 데이터를 주고받기 위해서는 IPC(Inter Process Communication)가 필요하다.
하지만 스레드를 생성하는 경우 메모리 구조는 다르다.
프로세스가 스레드A와 B를 생성한 경우 스레드를 생성할 때마다, 해당 스레드만을 위한 ThreadStack영역(실행 흐름의 추가를 위한 최소조건)만이 생성될 뿐, 나머지 영역(Code, Data, Heap)은 부모 프로세스 영역을 공유하고 있다. 스레드마다 스택을 독립적으로 할당해준다.