사실, 저희는 자바스크립트로 프로그래밍을 하면서 프로세스와 스레드를 직접적으로 설정하거나 관리하지는 않습니다.
물론, 다들 아시겠지만 자바스크립트는 직접적으로 프로세스와 스레드를 지원해 주는 언어와 달리, 직접적인 지원을 하지 않습니다.
그럼에도 불구하고, 프로세스와 스레드는 컴퓨터안에서 작동하는 모든 프로그램에 적용되는 개념이므로 꼭 알아둘 필요가 있는 중요한 개념입니다.
먼저, 프로세스와 스레드에 대한 간단한 정의부터 살펴보겠습니다.
프로세스는 보통 실행중인 프로그램을 말합니다. 윈도우의 작업 관리자(혹은 맥의 활성 상태)를 열어 프로세스 항목을 보면, 굉장히 많은 프로세스가 현재 실행중인 것을 알 수 있습니다.

이처럼, 우리가 컴퓨터를 사용하는 동안, 메모리 안에서는 새로운 프로세스들이 계속 생성되고, 사용되지 않는 프로세스는 메모리에서 삭제됩니다.
물론, 이런 프로세스들이 한 번에 다 사용되지는 않습니다. 일반적으로 하나의 cpu는 한 번에 하나의 프로세스만 실행할 수 있습니다. 따라서, cpu는 이 프로세스들을 조금 씩 번갈아 가며 실행합니다.
보다 자세히 보시기 위해서는 터미널에서 다음과 같이 쳐서 직접 확인해 볼 수 있습니다.

top라고 쳐서 확인해 보면, 다음과 같이 터미널에 현재 내 pc에서 운용중인 프로세스를 직접 실시간으로 살펴볼 수 있습니다.

이처럼 cpu는 한 프로세스를 실행하다가 또 다른 프로세스로 실행을 전환하고, 그 프로세스를 실행하다가 또 다른 프로세스의 실행으로 전환하는 것을 반복합니다.
우리는 앞서 프로세스가 프로그램을 실행하는 하는 것이라고 만 살펴봤습니다.
그렇다면, 이번에는 프로세스가 과연 어떤 동작 원리를 가지고 프로그램을 실행하는 지 살펴 볼 차례입니다.
먼저, 모든 프로세스를 실행하기 위해서는 CPU가 필요 하지만, 앞서 언급한 것처럼 CPU는 자원이 한정되어 있습니다.
즉, 모든 프로세스가 CPU를 동시에 이용할 수는 없습니다. 그렇기에 프로세스들은 차례대로 돌아가며 한정된 시간만큼만 CPU를 이용합니다.
자신의 차례가 되면 정해진 시간만큼 CPU를 이용하고 시간이 끝났음을 알리는 인터럽트(타이머 인터럽트)가 발생하면 자신의 차례를 양보하고 다음 차례가 올 때까지 기다립니다.
운영체제는 이를 위해서, 프로세스 제어 블록(=PCB)이라고 불리는 것을 운용합니다.
프로세스 제어 블록은 특정한 프로세스를 관리할 필요가 있는 정보를 포함하는 운영 체제 커널의 자료 구조입니다.
쉽게 말하면 운영체제가 프로세스를 제어하기 위해 프로세스의 상태 정보를 저장해 놓는 구조체입니다. 따라서 이 PCB마다 각자 각기 다른 값들을 가지고 있습니다. 마치 옷 가게에서 점원이 수많은 옷들 사이에 옷에 붙여진 태그로 옷과 관련된 정보를 판단하는 것처럼 운영체제도 수많은 프로세스들 사이에서 PCB로 특정 프로세스를 식별하고 해당 프로세스를 처리하는 데 필요한 정보를 판단합니다.
PCB는 운영체제마다 약간의 차이는 있지만, 다음 그림과 같은 항목들을 저장하고 있습니다.


계속 말씀 드렸던 것처럼, 프로세스는 계속 전환되면서 실행됩니다. 그러다 보면 각자 프로세스는 중간 정보의 값을 저장해 두어야만 합니다. 안 그러면 다시 돌아왔을 때, 정보를 잃어버리기 때문입니다.
이러한 중간 정보, 즉 하나의 프로세스 수행을 재게하기 위해 기억해야 할 정보를 문맥이라고 합니다. 하나의 프로세스 문맥은 해당 프로세스의 PCB에 표현되어 있습니다. 따라서 PCB에 기록되는 정보를 문맥이라고 봐도 무방합니다.

이처럼 기존 프로세스를 PCB에 백업하고, 새로운 프로세스를 실행하기 위해 문맥을 PCB로부터 복구하여 새로운 프로세스를 실행하는 것을 문맥교환이라고 합니다.
프로세스가 생성되면 커널영역에 PCB가 생성된다고 말씀드렸습니다. 그렇다면 사용자 영역에는 프로세스는 어떻게 배치될까요?
코드 영역
코드 영역은 텍스트 영역이라고도 부릅니다. 이곳에는 말 그대로 실행할 수 있는 코드, 즉 기계어로 이루어진 명령어가 저장됩니다. 코드 영역에는 데이터가 아닌 CPU가 실행할 명령어가 담겨있기 때문에 쓰기가 금지되어 있습니다. 다시 말해 코드 영역은 읽기 전용 공간입니다.
데이터 영역
데이터 영역은 잠깐 썼다가 없앨 데이터가 아닌 프로그램이 실행되는 동안 유지할 데이터가 저장되는 공간입니다. 이런 데이터로는 전역 변수가 대표적입니다.
힙 영역
힙영역은 프로그램을 만드는 사용자 즉, 프로그래머가 직접 할당할 수 있는 공간입니다. 프로그래밍 과정에서 힙 영역에 메모리 공간을 할당했다면 언젠가는 해당 공간을 반환해야 합니다. 만약 이 공간을 반환하지 않을 경우, 메모리 내에 계속 남아있어 메모리 누수(낭비)를 초래합니다.
스택 영역
스택영역은 데이터를 일시적으로 저장하는 공간입니다. 따라서 데이터를 일시적으로 저장하는 공간입니다. 일시적으로 저장할 데이터는 스택 영역에 PUSH되고 더 이상 필요없다면, POP됨으로써 스택 영역에서 사라집니다.
ex) 지역 변수, 매개 변수, 함수 리턴 값 등.

이번에는 앞서 설명드린 프로세스의 상태에 대해 조금 더 자세히 살펴보겠습니다.
아래 그림과 같이 프로세스는 총 5개의 상태를 가집니다.

먼저, 생성 상태에서는 말 그대로 프로세스를 생성합니다. 이제 막 메모리에 적재되어 PCB를 할당 받은 상태입니다. 생성 상태를 거쳐 실행할 준비가 완료된 프로세스는 곧 바로 실행되지 않고 준비 상태가 되어 cpu의 할당을 기다립니다.
준비상태는 당장이라도 cpu를 할당 받아 실행할 수 있지만, 아직 자신의 차례가 아니기에 기다리고 있는 상태입니다. 준비 상태 프로세스는 차례가 되면 cpu를 할당 받아 실행 상태가 됩니다.
이때 준비 상태인 프로세스가 실행상태로 전환되는 것을 디스패치라고 합니다.
실행상태는 cpu를 할당 받아 실행 중인 상태를 의미합니다. 실행 상태인 프로세스는 할당된 일정 시간 동안만 cpu를 사용할 수 있습니다. 이때 프로세스가 할당된 시간을 모두 사용하면 다시 준비상태가 되고, 실행 도중 입출력 장치를 사용하여 입출력 장치의 작업이 끝날 때까지 기다려야 한다면 대기 상태가 됩니다.
프로세스는 실행 도중 입출력 장치를 사용하는 경우가 있습니다. 입출력 작업은 cpu에 비해 처리 속도가 느리기에, 입출력 작업을 요청한 프로세스가 입출력 장치가 입출력을 끝날때까지 기다려야 합니다. 이렇게 입출력 장치의 작업을 기다리는 상태를 흔히 대기 상태라고 합니다.
종료 상태는 말 그대로 종료가 된 상태입니다. 프로세스가 종료되면 운영체제는 PCB와 프로세스가 사용한 메모리를 정리합니다.
사실 프로세스의 계층 구조를 통해 다양한 현상들이 나옵니다만, 이번시간에는 간단하게 개념 정도만 짚고 넘어가겠습니다.
앞서 말씀 드린 프로세스에도 계층이 있습니다.
부모 프로세스와 자식 프로세스.
프로세스는 실행 도중 시스템 호출을 통해 다른 프로세스를 생성할 수 있습니다. 이때 새 프로세스를 생성한 프로세스를 부모 프로세스, 부모 프로세스에 의해 생성된 프로세스를 자식 프로세스라고 합니다.

다음은 프로세스와 항상 붙어다니는 용어인 스레드입니다.
스레드는 실행의 단위입니다. 조금 더 정확하게 말하면 스레드는 프로세스를 구성하는 실행의 흐름 단위입니다.
💡 즉, 스레드란, 프로세스 내에서 실제로 작업을 수행하는 주체입니다.또, 하나의 프로세스는 여러 개의 스레드를 가질 수 있습니다. 따라서 스레드를 이용하면, 하나의 프로세스에서 여러 부분을 동시에 실행할 수 있습니다.
이런 스레드는 크게 두 가지 동작 원리로 다시 나뉩니다.

1) 싱글 스레드
싱글 스레드란 하나의 프로그램에서 동시에 하나의 코드만 실행할 수 있다는 뜻입니다.
즉, 싱글 스레드란 코드가 실행되서 끝난 지점과 다음 코드의 시작 지점이 연결된 형태입니다. 각 스레드는 한 번에 하나의 작업만 수행할 수 있습니다. 예를 들어, Task A, B, C가 있다고 치면, 이는 다음처럼 Task A —> Task B —> Task C 순으로 순차적으로 실행됩니다. (이때, 다음 작업을 시작하기 전에 이전 작업을 완료해야합니다.)
이러한, 작동원리로 인해 싱글 스레드는 각기 장 단점이 존재합니다.
1) 자원 접근에 대한 동기화를 신경쓰지 않아도 된다.
여러 개의 스레드가 공유된 자원을 사용할 경우 각 스레드가 원하는 결과를 얻게 하려면 공용 자원에 대한 접근이 통제되어야 하며 이 작업은 프로그래머에게 많은 노력을 요구하고 비용을 발생시킵니다. 하지만, 싱글 스레드 모델에서는 이러한 작업이 필요하지 않습니다.
2) 문맥 교환(context switch) 작업을 요구하지 않는다.
앞서 설명드린 문맥 교환 작업은 프로세스의 하위 실행체인 스레드에도 당연하게 적용됩니다. 만약 멀티 스레드로 처리한다면 문맥교환에 대한 작업을 직접 처리해 줘야만 합니다.
3) 단순히 CPU만을 사용하는 계산작업이라면, 오히려 멀티스레드보다 싱글스레드로 프로그래밍하는 것이 더 효율적이다.
=> a) 두 개의 작업을 하나의 스레드로 처리하는 경우 VS b) 두 개의 스레드로 처리하는 경우
b의 경우는 짧은 시간 동안 2개의 스레드가 번갈아가면서 작업을 수행합니다. 그래서 동시에 두 작업이 처리되는 것과 같이 느끼게 됩니다.하지만, 오히여 두 개의 스레드로 작업한 시간이 싱글스레드로 작업한 시간보다 더 걸릴 수도 있는데, 그 이유는 스레드 간의 작업전환(context switching)에 시간이 걸리기 때문입니다.
다시 말해서, 단순히 CPU만을 사용하는 작업은 싱글 스레드가 멀티 스레드보다 빠릅니다.
따라서 다시 정리해 보면,
프로그래밍 난이도가 쉽고, CPU, 메모리를 적게 사용한다. (코스트가 적게든다) 반면에, 멀티 스레드 모델은 프로그래밍 난이도가 높다. 또한, 스레드 수만큼 자원을 많이 사용한다.
1) 여러 개의 CPU를 활용하지 못한다.
싱글 스레드는, CPU의 성능을 최대한 끌어내지 않는다고 합니다. 즉, 동시 다발적으로 작업을 하지 않으므로, 여러 개의 CPU가 있어도 그 일부의 작업만 수행하게 됩니다.
2)연산량이 많은 작업을 하는 경우, 그 작업이 완료되어야 다른 작업을 수행할 수 있다.
예를 들어, 웹 게임에서 좌표를 계산하는데 3초가 걸리고 계산된 좌표를 받아 DOM에 반영한다고 생각해봅시다. 좌표를 계산하느라 3초간 DOM 업데이트 등의 다른 작업들을 수행할 수가 없습니다. 사용자 입장에서는 3초간 멍하니 기다릴 뿐입니다. 좌표를 동시에 여러 번 계산해야 하는 경우 더 심각해집니다. 좌표를 20번 계산하면 3 * 20 = 60초를 기다려야 하는 셈입니다.3초의 시간은 어쩔 수 없다 치더라도, 계산하는 동안 UI 클릭같은 다른 작업은 진행할 수 있어야 원활한 서비스를 제공할 수 있습니다. 이럴 때는 멀티 스레드가 필요해지는 순간입니다.
3) 싱글 스레드 모델은 에러 처리를 못하는 경우 멈춘다.
싱글 스레드 모델은 에러 처리를 못 하는 경우, 해당 프로그램의 실행이 곧바로 멈춰버리게 됩니다. 이에 반해 멀티 스레드는 다른 스레드에 해당 부분을 이양할 수 있기 때문에 실행이 멈추지 않습니다.
2) 멀티 스레드
다음, 멀티 스레드는 말 그대로 하나의 프로세스를 다수의 실행 단위로 구분하여 하나의 프로그램 안에서도 동시에 여러 개의 일을 수행할 수 있도록 하는 것을 의미 합니다.
ex) 멀티 스레드가 적용된 웹 브라우저 프로그램에서 하나의 스레드가 이미지 파일을 로드하고 있는 동안, 다른 스레드에서 사용자와 상호작용 가능
synchronized 키워드) 그러나 불필요한 부분까지 동기화를 하는 경우, 과도한 lock으로 인해 병목 현상을 발생시켜 성능이 저하될 가능성이 높기 때문에 주의해야 합니다.참고 자료.
https://www.slideshare.net/ssuserd5354e/process-232295835
https://zangzangs.tistory.com/107
https://jhnyang.tistory.com/33