iOS/개념

[iOS] Process, Thread, Task, sync, async, serial, concurrent 용어 정리

누알라리 2021. 12. 8. 23:06

안녕하세요.

GCD에 대해 정확히 알고있지 않은 것 같아서 공부를 하려고보니 얼레벌레 알고있던 용어들이 몇 개 있더군요.

멀티쓰레딩과 같이 많이 언급되는 개념들을 이곳저곳에서 모아 정리해보았습니다.

 


프로세스

개요

컴퓨터가 발전하면서 여러 프로그램이 메인 메모리에 적재되어 병행 실행되었다. 이런 변화는 컴퓨터의 효율을 높여주어지만, 프로그램에 대한 강력한 통제도 요구하기 시작했다. 이 때 프로세스라는 개념이 등장했다.

개념

프로세스란 간단히 실행중인 프로그램 이다.

이는 디스크에 저장되어 있던 응용 프로그램이 메모리에 적재되어 운영체제의 제어를 받는 상태를 말한다.

다시 말해, 해당 프로세스가 사용하고 있는 메모리 영역(자신의 주소공간)이 존재함을 의미한다.

프로세스는 메모리에 다음과 같은 주소 공간을 갖는 능동적인 객체 이다.

  1. 실행 스택(Stack)
    • 일시적인 데이터를 저장하는 영역
    • 호출된 함수의 복귀주소, 함수 안에서 선언된 지역변수, 매개변수, 리턴값 등이 저장되고 함수를 호출할수록 커지고 함수가 종료되면 제거된다.
    • 컴파일 타임에 크기가 결정되기 때문에 무한히 할당할 수 없으며, 재귀함수가 너무 깊게 호출되거나 함수 내 지역 변수의 크기가 stack 영역을 초과하면 stack overflow 에러가 발생한다.
  2. 실행 힙(Heap)
    • 개발자가 필요할 때 마다 사용하는 자유 메모리 영역.
    • 다른 영역들과는 다르게 Heap은 런타임에 크기가 결정되며, 동적 할당 등으로 Heap 영역의 메모리를 사용할 수 있다.
    • 사용한 다음에 반드시 해제해야 하며, 안그러면 Memory leak이 발생한다.
  3. 정적 변수(Data)
    • 코드에서 선언한 전역변수 또는 정적(static) 변수가 저장되는 영역.
    • 전역/정적 변수 값을 참조한 코드는 컴파일 후 프로세스 실행 중에 동적으로 Data 영역의 주소값을 가르키도록 바뀐다.
    • 실행 도중 전역 변수의 값이 바뀔수 있으니 읽고-쓰기가 가능한 영역이다.
    • 초기화되지 않은 전역 변수는 BSS 영역에 할당된다.
  4. 텍스트(Code)
    • 프로세스가 실행하는 코드가 저장되는 영역
    • 컴파일 타임에 결정되고 프로그램이 텍스트 영역을 침범하여 기록하려고 하면 오류가 발생하여 프로그램은 종료된다.

좀 더 복잡하게 보자면.....

사용자 관점의 프로세스

→ 세그먼트(코드, 데이터, 스택, 힙) 등 가상 주소 공간을 갖는 실행 상태

시스템 관점의 프로세스

→ 처리 상태에 있는 데이터 구조

  • 프로그램은 프로세서를 할당받아야 실행 상태의 프로세스가 될 수 있다.
    • 프로세서 할당 : 프로세스의 실행 순서를 결정하는 스케줄러(디스패칭)에 의해 할당
    • 파일에 관련된 자원에 대한 참조(장치 관리, 메모리 관리), 프로세스 지원과 협력에 관한 정보(교착상태, 보호, 동기화) 교환을 한다.

프로세스는 시스템에서 준비, 실행, 대기(보류) 상태를 변화하면서 실행된다.

스레드

개념

스레드는 간단히 말해서 프로세스(실행 중인 프로그램) 내에서 실제로 작업을 수행하는 주체를 말한다.

운영체제에서의 프로세스는

  1. 프로그램을 실행하는 자원
  2. 실행되는 제어의 흐름(디스패칭되는 개체)

두 가지 특성으로 나누어서 볼 수 있었다.

현대 운영체제는 프로세스에서 실행 제어만 분리한 실행 단위를 스레드(혹은 경량 프로세스) 라고 하고, 자원 단위의 처리를 프로세스로 나누어 처리한다.

스레드는 프로세스처럼 프로세서를 사용하는 기본 단위이면서 프로그램을 실행하는 프로세스 내의 개체, 즉 명령어를 독립적으로 실행할 수 있는 하나의 제어 흐름이다.

프로세스는 하나 이상의 스레드를 가지며, 각 스레드는 다음 내용을 포함한다.

  • 스레드 실행 정보(실행, 준비 등)
  • 실행 스택(주소 정보 세트)
  • 스레드 지역 데이터
  • 프로세스 메모리와 자원에 대한 접근 같은 스레드 실행환경 정보

→ 같은 프로세스에 속한 스레드들끼리는 data, code, heap 영역을 공유한다.

스레드를 사용하면 자원을 공유하며 한 프로세스에서 동시 작업이 가능하다.

즉, 프로세스에 포함된 스레드들은 공통 목적을 달성하기 위해 병렬로 수행된다.

스레드를 사용하면 얻는 이점은 무엇이 있을까?

  • 사용자에 대한 응답성 증가
    • 긴 작업 수행이나 응용 프로그램 일부분이 봉쇄되어도 다른 스레드에서 사용자에 응답 가능
  • 프로세스 자원과 메모리 공유 가능
  • 경제성
  • 다중 프로세서 구조 활용 가능

Task(테스크)

개념

비동기적으로 실행되는 단일 작업을 의미한다.

비동기 프로그래밍의 async, await 키워드와 같이 나오는 Task는 주로 Thread와 개념이 혼동된다.

Thread → 프로세스 내에서 실제 실행 되는 작업의 주체

Task → 비동기적으로 실행되는 단일 작업

자주 등장하는 용어들

sync (동기)

요청과 결과가 동시에 일어나는 것

요청한 작업이 끝나기 전까진 다른 작업을 수행할 수 없다.

단일 작업의 특성

async (비동기)

요청과 결과가 동시에 일어나지 않는 것

요청한 작업이 끝나지 않아도 동시에 다른 작업을 수행할 수 있는 것

단일 작업의 특성

Serial (하나씩 + 순차적)

단일작업들을 직렬로 하나씩 순차적으로 실행하는 개념

Apple에서 사용되는 Serial키워드는 GCD의 Main Queue가 SerialQueue.

따라서 Main Queue는 한 번에 하나의 Task만 차례대로 실행한다.

print("start")
DispatchQueue.main.async {
    for _ in 0...5 {
        print("async")
    }
}
for _ in 0...5 {
    print("sync")
}
print("end")

의 코드는.. Main Queue에서 실행되기 때문에 Serial하게 실행된다.

start
sync
sync
sync
sync
sync
end
async
async
async
async
async

async가 비동기니까 중간에

sync

async

sync

async

이렇게 나와야할 것 같지만, Serial Queue이기 때문에 하나의 Task만 작업할 수 있다.

따라서 같이 나오는게 아닌 직렬로 하나씩 실행하고 나서야 실행된다.

Serial Queue는 작업을 동기화할 때 많이 사용된다.

Concurrent (여러개 + 동시에)

동시에 여러개의 단일작업들이 병렬로 실행되는 개념

한 번에 여러개의 Task를 실행시킬 수 있다.

Apple에서는 Concurrent Queue를 직접 생성해야한다.

let concurrentQueue = DispatchQueue.init(label: "", attribute: .concurrent)
concurrentQueue.sync  { print("start") }
concurrentQueue.async { for _ in 0...5 { print("async") }}
concurrentQueue.sync  { for _ in 0...5 { print("sync") } }
concurrentQueue.sync  { print("end") }

병렬로 여러개의 Task들이 동시에 실행된다고 했으니까, 결과값은

start
sync
sync
async
sync
sync
sync
end
async
async
async
async

이런식으로 출력된다.

Concureent Queue는 주로 작업을 수행할 때 사용된다.