프로세스와 스레드

Kiwoong Park·2023년 7월 8일
0

프로그램? 프로세스?

프로그램은 윈도위의 *.exe, mac의 *.dmg 파일과 같이 컴퓨터에서 실행할 수 있는 파일 을 말한다. 파일을 실행하지 않은 상태인 정적 프로그램을 보통 프로그램이라고 한다

프로세스는 정적인 프로그램을 동작 시켜 프로그램이 돌아가고 있는 상태를 의미한다. 즉, 컴퓨터에서 작업 중인 프로그램을 프로세스라고 한다.

프로세스와 스레드의 차이

🚢 프로세스 :

  • 운영체제(OS)로부터 시스템 자원(RAM, 시스템 변수, 환경변수 등)을 할당 받아 실행 중인 프로그램의 인스턴스
  • 각 프로세스는 독립된 메모리 공간을 가지고 있으며, 프로세스 간에는 메모리를 공유할 수 없음
  • 각 프로세스는 자신만의 주소 공간, 파일 디스크립터, 환경 변수, 스레드 등을 가지고 있음
  • 프로세스는 일반적으로 별도의 주소 공간에서 실행되므로, 프로세스 간의 통신에는 IPC(Inter-Process Communication)매커니즘이 필요하다.

🚣 스레드 :

  • 프로세스가 할당받은 자원을 이용해 프로세스 내에서 실행되는 작은 실행 단위
  • 한 프로세스 내에서 여러 개의 스레드를 생성하여 병렬적으로 작업을 수행할 수 있다.
  • 스레드는 프로세스의 자원을 공유하며, 스레드 간에는 같은 주소 공간을 공유한다.
  • 스레드는 생성과 관리에 대한 오버헤드가 작기 때문에, 프로세스 간의 전환보다 빠르게 실행될 수 있다.
  • 하지만, 스레드 간의 동기화와 공유 자원에 대한 접근 제어가 필요하기 때문에 적절한 동기화 메커니즘이 필요하다.

요약
: 프로세스는 독립된 실행 환경을 가지고 있는 반면 스레드는 프로세스 내에서 실행되는 작은 실행 단위로 자원을 공유

프로세스의 한계점

  • 프로세스는 생성과 전환에 많은 자원과 시간이 소모되며, 컨텍스트 스위칭 비용도 상당히 크다.
  • 프로세스의 한계점 중 하나는 이러한 자원 소모와 컨텍스트 스위칭 비용 때문에 병렬 작업을 효율적으로 처리하기 어렵다는 점이다.
  • 특히, CPU 코어의 개수가 증가하면서 다중 프로세스로 병렬 처리를 시도하는 경우, 프로세스 간의 통신 및 동기화에 대한 부담이 커져 전체적인 성능 향상을 제한하는 요인이 될 수 있다.

스레드 등장 배경

👨‍💻👨‍👧‍👧🗂예를 들어, 한 개의 크롬 브라우저를 켜서 여러 텝을 통해 웹서핑, 온라인 쇼핑 결제, 웹 디스코드 화상미팅을 동시에 할 수 있는 이유가 여러 가지의 작업들의 흐름이 다중의 스레드를 통해 이뤄지기 때문이다.

  • 자원 절약: 스레드는 프로세스의 자원을 공유하므로, 프로세스 생성 및 메모리 할당 등의 비용을 절약할 수 있다.
  • 응답성 향상: 멀티스레딩을 통해 작업을 분할하고 병렬로 처리함으로써 응답 시간을 줄일 수 있다. 한 스레드가 작업을 수행하는 동안 다른 스레드는 계속 실행되므로 전체적인 처리 시간을 단축시킬 수 있다.
  • 병렬성 증가: 스레드는 동시에 실행될 수 있기 때문에 다중 프로세서 시스템에서 병렬 처리를 할 수 있다. 이를 통해 작업의 성능과 처리량을 향상시킬 수 있다.

스레드 사용시 주의할 점

  • 스레드는 공유 자원에 대한 동시 접근으로 인해 동기화 문제가 발생할 수 있으며, 이로 인해 경합 상태나 교착상태와 같은 문제가 발생할 수 있다.
  • 스레드 간의 상호작용이 복잡해질 수 있어 디버깅과 관리가 어려워질 수 있다.

프로세스의 자원 구조

  1. Code (코드): 프로그램의 명령어들이 저장되는 영역이다. 실행 가능한 명령어들(CPU가 해석 가능한 기계어 형태)로 구성되어 있다.

  2. Data (데이터): 전역 변수와 정적 변수 등의 데이터가 저장되는 영역이다. 프로그램의 초기화된 데이터들이 위치한다.
    데이터 영역은 프로세스의 실행 시작 시 메모리에 할당되며, 컴파일 타임에 할당되는 영역이기 때문에 크기가 정적으로 결정된다. 또한, 데이터 영역은 프로세스의 다른 영역인 코드(Code), 스택(Stack), 힙(Heap)과는 별도로 관리되며, 프로세스의 수명 동안 메모리에 고정된 위치에 상주합니다.
    데이터영역은 .data ,.rodata, .bss 영역으로 세분화된 섹션으로 구성될 수 있음.
    1) .data 섹션 (Initialized Data Section):
    .data 섹션은 초기화된 전역 변수와 정적 변수의 데이터를 저장하는 영역이다. 프로그램이 실행되기 전에 이미 초기화된 값들이 들어간다. 이 섹션은 실행 파일의 이미지에 실제로 데이터 값을 포함하고 있으며, 프로그램이 실행 중에 해당 데이터에 접근할 수 있다. 일반적으로 전역 변수와 정적 변수가 .data 섹션에 할당된다.

    2) .bss 섹션 (Uninitialized Data Section):
    .bss 섹션은 초기화되지 않은 전역 변수와 정적 변수의 데이터를 저장하는 영역이다. 이 섹션에는 값이 할당되지 않은 변수들이 위치하며, 실행 파일의 이미지에는 실제 데이터 값이 포함되지 않는다. 대신 프로그램이 실행될 때 변수들은 자동으로 0 또는 null로 초기화된다. 이렇게 초기화되지 않은 데이터의 크기만을 저장해둔다고 생각할 수 있다.

    3) .rodata 섹션 (Read-Only Data Section):
    .rodata 섹션은 읽기 전용 데이터를 저장하는 영역이다. 이 섹션에는 프로그램 내에서 사용되는 상수, 문자열 리터럴 등이 저장된다. .rodata 섹션의 데이터는 실행 중에 수정되지 않으며, 읽기만 가능하다. 일반적으로 문자열 상수와 같은 읽기 전용 데이터가 .rodata 섹션에 할당된다.

    요약하자면, 데이터 영역은 전역 변수, 정적 변수, 상수와 같은 프로그램의 데이터를 저장하고 관리하는 영역이다.

  3. Stack (스택): 함수 호출과 로컬 변수들이 저장되는 영역이다. 함수가 호출될 때마다 스택 프레임이 생성되고, 함수의 실행이 끝나면 해당 스택 프레임이 제거됩니다. 스택은 후입선출 (LIFO) 구조로 동작합니다. stack 영역을 초과하면 stack overflow 에러가 발생한다.

  4. Heap (힙): 동적으로 할당된 메모리를 관리하는 영역이다. 프로그램 실행 중에 동적으로 메모리를 할당하고 해제하는 데 사용된다. 주로 동적으로 생성된 객체, 배열 등이 힙에 저장된다. 힙은 런타임에 메모리가 동적으로 할당되므로 크기가 동적으로 변경될 수 있다.
    1) 동적 메모리 할당: 힙 영역은 프로그램 실행 중에 동적으로 메모리를 할당하는 데 사용된다. 동적 메모리 할당은 프로그램에서 필요에 따라 메모리 공간을 동적으로 확보하는 방법으로, malloc(), calloc(), realloc()과 같은 함수를 사용하여 할당된다.

    2) 할당과 해제: 힙 영역에서는 메모리 블록을 할당하고 사용한 뒤, 더 이상 필요하지 않을 때 메모리를 해제해야 한다. 메모리 누수를 방지하기 위해 할당된 메모리를 적절히 해제해야 한다. 일반적으로는 free() 함수를 사용하여 할당된 메모리를 해제한다.

    3) 크기의 동적 변경: 힙 영역에서는 동적으로 할당된 메모리의 크기를 변경할 수도 있다. realloc() 함수를 사용하여 메모리 블록의 크기를 재조정할 수 있다. 이를 통해 메모리의 크기를 늘리거나 줄일 수 있다.

    4) 메모리 관리: 힙 영역에서는 메모리 관리를 위해 메모리 할당과 해제를 적절히 관리해야 한다. 이는 프로그래머의 책임이며, 잘못된 메모리 관리는 메모리 누수(memory leak)나 덮어쓰기(overwrite) 등의 문제를 초래할 수 있다.

프로세스는 위와 같은 자원들로 구성되어 있으며, 각 영역은 프로세스 메모리 공간에서 서로 다른 위치를 차지한다. 이러한 자원 구조를 효율적으로 활용하여 프로세스는 작업을 수행하고 필요한 데이터와 메모리를 관리한다.

스레드의 자원 공유

스레드가 여러 개 있어서 우리는 웹 브라우저를 통해 웹 서핑과 동시에 파일 다운로드가 가능하게 된다. 스레드끼리 프로세스의 자원을 공유하면서 프로세스 실행 흐름의 일부가 되기 때문에 동시 작업이 가능하다.

스레드의 자원 공유는 동시에 여러 스레드가 동일한 데이터나 리소스에 접근하면서 문제가 발생할 수 있다. 이를 해결하기 위해 스레드 간의 자원 공유는 아래와 같은 개념들을 활용한다.

  1. 경쟁 상태 (Race Condition): 경쟁 상태는 여러 스레드가 동시에 자원에 접근하고 변경하려는 경우 발생하는 문제다. 예를 들어, 한 스레드가 값을 변경하고 있는 동안 다른 스레드가 동일한 값을 읽을 경우 예측할 수 없는 결과가 발생할 수 있다.

  2. 상호 배제 (Mutual Exclusion): 상호 배제는 동시에 여러 스레드가 자원에 접근하지 못하도록 하는 메커니즘이다. 상호 배제를 통해 한 번에 하나의 스레드만 자원에 접근할 수 있도록 제어한다. 이를 통해 경쟁 상태를 예방하고 자원의 일관성을 유지할 수 있다.

  3. 임계 영역 (Critical Section): 임계 영역은 상호 배제를 적용해야 하는 코드 영역을 의미한다. 임계 영역에 진입하기 위해서는 락(lock) 또는 세마포어 등의 동기화 메커니즘을 사용하여 다른 스레드가 접근하지 못하도록 한다.

  4. 동기화 (Synchronization): 동기화는 스레드 간에 작업을 조율하고 순서를 제어하는 메커니즘이다. 동기화를 통해 스레드가 올바른 순서로 작업을 수행하도록 하고, 상호 배제를 통해 자원에 대한 안전한 접근을 보장한다.

profile
You matter, never give up

0개의 댓글