프로세스(Process)와 스레드(Thread)

dong5854·2022년 3월 9일
0

프로그래밍 공부를 하다보면 프로세스와 스레드에 관한 내용을 많이 듣게된다. 하지만 이 둘이 어떻게 다르고 구체적으로 어떤 차이가 있는지 잘 알지 못하고 관련 내용들을 공부하면 결국 그 내용을 온전히 이해하기가 어려웠기 때문에 이번 기회에 이 둘에 대해 공부한 것들을 기록해두려한다.


프로그램(Program)과 프로세스(Process)

프로세스와 스레드에 대해 알기전에 먼저 프로그램과 프로세스의 차이에 대해 알아보자.

프로그램: 실행되기 전 상태의 명령어, 코드 및 정적인 데이터의 묶음

프로세스: 실행중인 프로그램, 컴퓨터로부터 자원을 할당 받는 작업의 단위

즉, 프로그램은 실행할 수 있는 파일이고, 프로세스는 실행되고 있는 컴퓨터 프로그램이다.


그렇다면 프로그램이 실행되어 프로세스가 되면 어떤 일이 일어날까?

  1. 메모리 영역에 프로세스의 주 구성 요소인 Stack, Heap, Data, Code가 올라간다.

    Stack영역: 지역변수와 함수 인자 값, 매개변수 반환값등의 일시적인 데이터가 저장되는 영역
    Heap 영역: 동적 메모리 호출에 의해 할당되는 메모리 영역, C언어의 malloc()과 calloc() 함수에 의해 생성된 변수들이 이곳에 할당된다.
    Data 영역: 프로그램의 전역변수(Global Variable)과 정적 변수(Static Variable)이 저장되는 있는 영역
    Code 영역: 자료에 따라 Text영역이라고도 하고, 프로그램의 코드 그 자체를 뜻한다. 이 코드들은 CPU가 해석할 수 있는 Binary Code 상태로 올라간다.

  2. 해당 프로세스에 대한 정보를 담고 있는 PCB(프로세스 제어 블록,Process Control Block)블록이 만들어진다.

    프로세스 제어 블록은 운영체제가 프로세스를 제어하기 위해 정보를 저장하는 곳으로, 프로세스의 상태 정보를 저장하는 자료구조이다. PCB는 운영 체제가 프로세스를 표현한 것이라고 한다. 운영체제에 따라 PCB에 포함되는 항목이 다를 수 있지만, 일반적으로는 다음과 같은 정보가 포함된다.

    이미지 출처: https://yoongrammer.tistory.com/52
    포인터(Pointer): 프로세스의 현재 위치를 저장하는 포인터 정보
    프로세스 상태(Process State): 프로세스의 각 상태를 저장한다. 프로세스의 상태로는 생성(Created), 준비(Ready), 실행(Running), 대기(Waiting), 종료(terminated)가 있다.
    프로세스 식별자(PID, Process Number): 어떤 한 프로세스를 일시적으로 식별 할 수 있다. 프로세스의 우선순위를 조정하거나 종료하는 등의 다양한 함수 호출에 사용된다.
    프로그램 카운터(Program Counter): 프로세스를 위해 실행될 다음 명령어의 주소를 포함하는 카운터를 저장한다.
    레지스터(Registers): 누산기, 베이스, 레지스터 및 범용 레지스터를 포함하는 CPU 레지스터에 있는 정보
    메모리 제한(Memory Limit): 운영 체제에서 사용하는 메모리 관리 시스템에 대한 정보가 포함된다.
    열린 파일 목록(Open File Lists): 프로세르를 위해 열린 파일 목록이 포함된다.
    여기 나와있는 정보들 외에도 많은 정보들이 있다.


이미지 출처: https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html

위의 이미지를 보며 정리한 내용을 다시 본다면 조금 더 쉽게 이해가 가능할 것 같다.


프로세스(Process)와 스레드(Thread)

이제 프로그램과 프로세스가 무엇인지는 조금이나마 알 것 같다. 그렇다면 스레드는 무엇일까?

스레드: 프로세스의 실행 단위

프로세스 안에서 일어나는 여러 갈래의 작업을 스레드라고 한다.

프로세스(Process) VS 스레드(Thread)

CPU(프로세서)는 한 순간에 하나의 프로세스만 돌릴 수 있다.
이 말을 처음들으면 이상하다고 생각된다. 분명 우리는 컴퓨터를 실행하며 여려가지 프로세스를 동시에 돌리고 있기 때문이다. 하지만 사실은 컴퓨터가 여러가지 프로세스를 동시에 돌리는 것이 아니라 운영체제가 짧은 시간에 빠르게 프로세스를 교체하면서 실행하고 있기 때문에 동시에 여러 개의 작업이 실행되고 있다고 느끼는 것이다.

Context Switching
이렇게 프로세스를 교체해가며 실행하기 위해서 현재 진행하고 있는 Task(Process, Thread)의 상태를 저장하고 다음 진행할 Task의 상태 값을 읽어 적용한다 좀 더 쉽게 말하자면 CPU가 여러 Task를 교체해가며 실행하는 것이다.

이 Context Switching에는 몇가지 단점이 있는데 이는 아래와 같다.

  1. Context Switching을 하는 과정에서 프로세스의 4가지 구성 요소인 Stack, Heap, Data, Code가 로딩되고, 다음 프로세스로 넘어갈 때 현재 실행중이던 프로세스의 Stack, Heap, Data, Code를 내리고 다음 프로세스의 Stack, Heap, Data, Code를 로딩하는 작업이 필요하다.

  2. 다른 프로세스의 정보를 이용하기 위해서 통신을 해야한다. 같은 작업을 하기 위해 만들어진 프로세스들도 각각의 프로세스가 다른 Stack, Heap, Data, Code 영역을 가지기 때문에 다른 프로세스에 있는 정보를 사용하기 위해서는 통신이 필요하다.

이러한 단점을 해결하기 위해 나온 개념이 스레드(Thread)이다.

먼저 스레드의 구조를 한번 확인해보자.

이미지 출처: https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html

위의 이미지를 보면 스레드는 같은 프로세스 안에서 Code, Data, Heap 영역을 공유하는 것을 볼 수 있다. 이렇게 공유되는 자원이 있기 때문에 Context Switching이 빠르게 이루어 질 수 있다. 또한 같은 자원을 공유하기 때문에 스레드끼리의 커뮤니케이션이 프로세스간의 커뮤니케이션에 비해 더 효율적이다.

스레드의 단점
지금까지 본 내용들만 생각한다면 스레드가 프로세스에 우월하다고 생각이 된다. 하지만 스레드는 스레드만의 단점이 존재한다.

  1. 하나의 스레드에 문제가 생기면 전체 프로세스에 영향을 미친다.
  2. 자원을 공유하기 때문에 동기화 문제가 발생할 수 있다.
  3. 디버깅이 어렵다.

멀티 프로세스(Multi-Process)와 멀티 스레드(Multi-Thread)

일단 멀티 프로세스와 멀티 스레딩은 공통적으로 CPU의 최대 활용을 위해 프로그램의 둘 이상의 부분을 동시에 실행하는 기술이다.

멀티 프로세스는 부모 프로세스가 자식 프로세스를 fork()하여 자식 프로세스를 여러개 만들어 일을 처리하도록 한다.
이때 자식 프로세스는 부모와 별개의 메모리 영역을 확보하게 된다.

스레드는 한 프로세스 내에서 구분된 실행 단위이다.
프로세스 내에서 분리해서 여러 스레드로 나뉘어서 실행단위가 나뉘어지면 멀티스레드이다.

멀티 코어(Multi-Core)

멀티 프로세스와 멀티 스레드는 소프트웨어적인 처리 방식에 대한 내용이라면 멀티 코어는 하드웨어적인 접근을 해야 이해하기 쉽다.

멀티코어를 이해하기 위해서는 동시성(Concurrency)과 병렬성(Prarallelism)을 알아야 한다.

동시성은 위에서 설명한 것처럼 Context Switcing이 빠르게 일어나 사용자 입장에서는 이들이 동시에 일어나는 것처럼 보이게 하는 것이다.

병렬성복수의 물리적인 코어를 사용해 복수의 프로세스를 정말로 동시에 처리하는 것이다.


내가 헷갈렸던 부분들

CPU는 한번에 하나의 프로세스만 실행 가능하다고 했는데 그럼 스레드는 하나의 프로세스에서 일어나는 작업이니까 여러개가 동시에 일어날 수 있나?

  • 스레드도 Context Switching의 비용이 적은 것 뿐이지 한번에 하나만 실행 가능한 것은 같다.

프로세서와 CPU코어는 같은 것인가?

  • 하나의 프로세서에서 여러개의 CPU 코어가 존재 할 수 있다. 즉 프로세서와 코어는 다른 것이다.
    리눅스 시스템에서 cat /proc/cpuinfo로 cpu 사양을 확인 할 수 있는데,
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 85
model name      : Intel(R) Xeon(R) Gold 5220 CPU @ 2.20GHz
stepping        : 7
microcode       : 0x5002f00
cpu MHz         : 2194.923
cache size      : 25344 KB
physical id     : 0
siblings        : 2
core id         : 0
cpu cores       : 2
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush acpi mmx fxsr sse sse2 ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single pti intel_ppin ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt clwb xsaveopt xsavec xgetbv1 xsaves pku ospke flush_l1d
bugs            : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa itlb_multihit
bogomips        : 4389.76
clflush size    : 64
cache_alignment : 64
address sizes   : 46 bits physical, 48 bits virtual
power management:

processor       : 1
vendor_id       : GenuineIntel
cpu family      : 6
model           : 85
model name      : Intel(R) Xeon(R) Gold 5220 CPU @ 2.20GHz
stepping        : 7
microcode       : 0x5002f00
cpu MHz         : 2194.923
cache size      : 25344 KB
physical id     : 0
siblings        : 2
core id         : 2
cpu cores       : 2
apicid          : 2
initial apicid  : 2
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush acpi mmx fxsr sse sse2 ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single pti intel_ppin ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt clwb xsaveopt xsavec xgetbv1 xsaves pku ospke flush_l1d
bugs            : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa itlb_multihit
bogomips        : 4389.76
clflush size    : 64
cache_alignment : 64
address sizes   : 46 bits physical, 48 bits virtual
power management:

위의 사양을 보면 프로세서는 2개인데 각각의 프로세서당 2개의 코어를 가지고 있어 총 4코어이다. 자세한 설명은 내가 참고한 블로그에서 더 볼 수 있다.

참고자료

https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4_%EC%A0%9C%EC%96%B4_%EB%B8%94%EB%A1%9D
https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4_%EC%8B%9D%EB%B3%84%EC%9E%90
https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html
https://yoongrammer.tistory.com/52
https://everybe-ok.tistory.com/15
https://goldsony.tistory.com/44
https://brad903.tistory.com/entry/%ED%94%84%EB%A1%9C%EC%84%B8%EC%84%9C%EC%99%80-%EC%BD%94%EC%96%B4%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90
https://applefarm.tistory.com/105?category=926699
https://www.youtube.com/watch?v=RrfASw-jfZ4
https://www.youtube.com/watch?v=dzfij2nZbRw
https://www.youtube.com/watch?v=iks_Xb9DtTM
https://www.youtube.com/watch?v=QmtYKZC0lMU
https://www.youtube.com/watch?v=1grtWKqTn50
https://www.youtube.com/watch?v=DmZnOg5Ced8

profile
https://github.com/dong5854?tab=repositories

0개의 댓글