CS/운영체제

[2주차] 프로세스와 스레드

mint* 2024. 8. 22. 21:57
728x90

프로세스와 스레드

📎 프로세스

프로그램에 대해 설명해주세요.

  • 저장장치에 저장되어 있는 데이터, 정적인 상태
    • 하드디스크 같은 저장장치에 보관되어 있다가 마우스로 더블클릭하면 실행된다.

 

프로세스에 대해 설명해주세요.

  • 프로그램을 메모리에 적재하여 실행, 동적인 상태
    • 실행중인 프로그램
  • 컴퓨터 시스템의 작업 단위(task)
  • 프로세스 종류
    • 포그라운드 프로세스 : 사용자가 보는 앞에서 실행되는 프로세스
      • 사용자와 상호작용
    • 백그라운드 프로세스(=daemon): 사용자의 뒷편에서 실행되는 프로세스

 

프로그램 -> 프로세스

    • 운영체제는 프로그램을 메모리의 사용자 영역의 적당한 위치로 가져온다.
    • 동시에, 커널 영역에 프로세스 제어 블록(PCB)를 생성하여 프로세스를 처리하는데 필요한 정보를 기록한다.
프로세스가 종료되었을 경우 프로세스가 메모리에서 삭제되고 PCB는 폐기된다.

 

프로세스 제어블록(PCB)에 대해 설명해주세요.

  • 프로세스와 관련된 정보를 저장하는 자료 구조
  • 메모리의 커널 영역에 생성된다.
    • 운영체제는 PCB로 프로세스를 식별하고 해당 프로세스를 처리하는데 필요한 정보를 얻는다.

 

PCB에는 어떤 정보가 담겨있을까요?

  • 프로세스 구분자(PID): 프로세스를 식별하기 위해 부여하는 고유 번호
  • 레지스터 값: 프로세스가 사용했던 중간값 저장
    • 자신의 실행 차례가 돌아오면 이전까지 사용했던 레지스터의 중간값들을 모두 복원하여 작업을 이어서 진행한다.
  • 프로세스 상태: 현재 프로세스 상태 정보 저장
    • 입출력 대기 상태인지, cpu 사용 대기 상태인지, cpu 이용 상태인지 구분한다.
  • CPU 스케줄링 정보: 프로세스가 언제, 어떤 순서로 cpu를 할당받을지에 대한 정보
  • 메모리 관리 정보: 프로세스의 메모리 주소 정보 저장
    • 베이스 레지스터, 한계 레지스터, 경계 레지스터
  • 사용한 파일과 입출력 장치 목록: 프로세스가 실행 과정에서 사용된 특정 입출력장치나 파일

 

프로세스 문맥에 대해 설명해주세요.

  • 하나의 프로세스 수행을 재개하기 위해 기억해야 할 정보
  • PCB에 기록된다.

 

문맥 교환(context switch)에 대해 설명해주세요.

  • 프로세스 간에 실행을 전환하는 것

 

문맥 교환 발생 과정에 대해서 조금 더 상세히 설명해주세요.

  • 기존 프로세스 문맥을 PCB에 백업하고, 새로운 프로세스를 실행하기 위해 문맥을 PCB로부터 복구하여 새로운 프로세스를 실행하는 것
    • 기존 프로세스와 새로운 프로세스의 PCB를 교환하는 작업
    • 프로세스가 빨리 번갈아 가며 수행되면 문맥 교환이 많이 발생하며, 프로세스가 동시에 실행되는 것처럼 보인다.
    • 오버헤드가 발생할 수 있다.

 

문맥 교환은 언제 발생하나요?

  • 타임아웃 : 한 프로세스가 자신에게 주어진 시간을 다 사용하면 발생한다.
  • 인터럽트
    • 한 프로세스가 자신에게 주어진 메모리 공간을 넘어가려 한다면 인터럽트가 발생한다.
    • 실행중인 프로세스의 PCB를 저장한 후, 인터럽트 프로세스는 해당 프로세스를 강제로 종료하고 인터럽트 처리를 마친다.

 

프로세스의 메모리 공간에 대해 설명해주세요.

  • 프로세스는 메모리의 사용자 영역에 배치된다.
    • 하나의 프로세스는 코드 영역, 데이터 영역, 힙 영역, 스택 영역으로 나뉘어 저장된다.

 

코드 영역(code, text)

  • CPU가 실행할 명령어가 저장된다.
    • 명령어는 기계어로 이루어진다.
  • 읽기 전용 공간이다.

 

데이터 영역

  • 프로그램이 실행되는 동안 유지할 데이터가 저장된다.
    • 전역 변수
    • 상수(읽기 전용)
  • 데이터는 변하므로 읽기, 쓰기 모두 가능하다.

코드 영역과 데이터 영역은 그 크기가 변하지 않는 정적 할당 영역이다.

  • 코드 영역은 프로그램을 구성하는 영역이므로 변경되지 않는다.
  • 데이터 영역은 프로그램이 실행되는 동안 유지되므로 변경되지 않는다.

 

힙 영역

  • 프로그래머가 직접 할당할 수 있는 저장 공간
    • 런타임에 크기가 결정되거나 변경될 수 있는 변수들을 저장
    • 필요할 때 할당하고, 필요 없을 때 해제해야 한다.
  • 메모리 누수 : 메모리 공간을 반환하지 않을 경우 할당한 공간은 메모리에 계속 남아 메모리 낭비를 초래한다.
  • 힙 영역은 메모리의 낮은 주소에서 높은 주소로 할당된다.

 

스택 영역

  • 함수 호출과 관련된 데이터를 일시적으로 저장하는 공간
    • 데이터 영역과 달리 프로그램 도중에 잠깐 쓰이는 값
    • 매개 변수, 지역 변수
    • 컴파일러가 자동으로 관리하며, 함수 호출과 함께 할당되고 종료(함수 scope 벗어날)시 해제된다.
    • 컴파일시에 크기가 결정된다.
  • 스택 영역은 높은 주소에서 낮은 주소로 할당된다.

힙 영역과 스택 영역은 실시간으로 그 크기가 변경되는 동적 할당 영역이다.

  • 힙 영역: 변수 동적 할당/해제
  • 스택 영역: 함수 호출시 스택 영역에 스택 프레임이 생성되고, 종료시 제거된다.

 

프로세스 수행 상태 변화 과정에 대해 설명해주세요.

프로세스 상태 다이어그램

프로세스 상태

    • 생성 상태(new): 프로세스를 생성 중인 상태
      • 이제 막 메모리에 적재되어 PCB를 할당받은 상태
    • 준비 상태(ready) : CPU 할당을 기다리는 상태
      • dispatch: 준비 상태인 프로세스가 실행 상태로 전환되는 것
    • 실행 상태(running) : CPU를 할당받아 실행 중인 상태
      • 할당된 일정시간 동안만 CPU를 사용할 수 있다.
      • 실행 상태 -> 준비 상태: CPU 할당시간을 다 사용하면 타이머 인터럽트가 발생하여 준비 상태가 된다.
      • 실행 상태 -> 대기 상태: 실행 도중 입출력 장치를 사용하여 입출력 장치의 작업이 끝날때까지 대기해야한다면 대기 상태가 된다.
    • 대기 상태(blocked) : 입출력 장치의 작업을 기다리는 상태
      • 대기 상태 -> 준비 상태: 입출력 장치의 작업이 끝나면 준비 상태가 된다.
    • 종료 상태(terminated) : 프로세스가 종료된 상태
      • 프로세스가 종료되면 운영체제는 PCB와 프로세스가 사용한 메모리를 정리한다.
오류나 다른 프로세스에 의해 비정상적으로 종료될 경우(abort) 디버깅을 위해 강제 종료 직전의 메모리 상태를 저장장치로 옮긴다(core dump)

 

프로세스 계층 구조

    • 부모 프로세스 : 새 포르세스를 생성한 프로세스
    • 자식 프로세스: 부모 프로세스에 의해 생성된 프로세스
      • 부모 프로세스와 다른 PID 를 가진다.
  • 최초의 프로세스의 PID는 1이며, 모든 프로세스의 부모 프로세스이다.
    유닉스 : init
    리눅스: systemd
    macOS: launchd

 

프로세스 생성 기법

  • 부모 프로세스fork()를 통해 자신의 복사본을 자식 프로세스로 생성한다.
  • 자식 프로세스exec() 를 통해 자신의 메모리 공간을 다른 프로그램으로 교체(덮어쓰기)한다.

 

fork() 명령어에 대해 설명해주세요.

    • 실행 중인 프로세스로부터 새로운 프로세스를 복사하는 시스템 호출
      • 부모 프로세스의 자원들(메모리 내용, 열린 파일 목록 등)이 자식 프로세스에 상속된다.
      • 부모 프로세스와 자식 프로세스는 PID, 메모리 정보, PPID(부모 프로세스 구분자), CPID(자식 프로세스 구분자)가 다르다.
부모 프로세스와 자식 프로세스는 같은 가상 주소를 사용하더라도, 실제로 다른 물리적 메모리를 가리킨다.

 

fork() 장점

  • 프로세스의 생성 속도가 빠르다.
    • 하드디스크로부터 가져오지 않고, 기존 메모리에서 복사하기 때문이다.
  • 추가 작업 없이 자원을 상속할 수 있다.
    • 부모 프로세서가 사용하던 모든 자원을 추가 작업없이 자식 프로세스에 상속할 수 있다.
  • 시스템 관리를 효율적으로 할 수 있다.
    • 자식 프로세스가 종료되면 부모 프로세스가 자식이 사용하던 자원을 정리한다.

 

exec()

  • 기존의 프로세스를 새로운 프로세스로 전환(덮어쓰는) 시스템 호출
    • 프로세스는 그대로 둔 채, 내용만 바꾼다.
  • 이미 만들어진 프로세스의 구조를 재활용한다.
    • PID, PPID, CPID 만 남겨두고 프로세스의 나머지 내용을 새로운 것으로 바꾼다.
    • 이미 만들어진 PCB, 메모리 영역, 부모자식 관계를 그대로 사용하고 코드 영역만 새롭게 가져오면 되므로 운영체제 작업이 수월하다.

exec()을 호출하지 않으면 부모 프로세스와 자식 프로세스는 같은 코드를 병행 실행하는 프로세스가 된다.

 

프로세스 계층구조 장점

    • 여러 작업을 동시에 처리할 수 있다.
      • fork()로 여러 프로세스를 만들어 동시에 처리한다.
    • 용이한 자원 회수
      • 부모-자식 관계로 프로세스를 만들면 자식 프로세스의 자원을 부모가 회수한다.
      • exec()을 이용해 부모-자식 관계를 유지하며 (프로세스 구조를 재활용)하여 새로운 프로세스로 전환한다.
부모 프로세스는 wait()을 호출하여 자식이 종료될때까지 block된다.
자식 프로세스는 exit()을 호출하여 커널에게 종료 상태를 알리고, 부모 프로세스의 대기 상태가 끝나며 자식 프로세스가 사용했던 자원을 커널에게 반납한다.

 

고아 프로세스

  • 부모 프로세스가 자식 프로세스보다 먼저 종료될 경우 wait()을 호출할 부모 프로세스가 사라진 자식 프로세스를 고아 프로세스라고 한다.
    • init 프로세스가 부모 프로세스가 된다.

 

좀비 프로세스

  • 자식 프로세스가 종료했음에도 부모가 wait() 호출하지 않아 자원을 반납하지 못하고 살아있는 상태
    • 부모 프로세스가 wait()을 호출하여 자식 프로세스의 종료 상태를 확인한다.

 

멀티 프로세스에 대해서 설명해주세요.

  • 하나의 프로그램을 여러 프로세스로 분리하여 동시에 실행하는 것
  • 여러 프로세스가 동시에 실행되어 한 프로세스가 죽어도 프로그램이 죽지 않아 프로그램 전체의 안전성이 높아진다.
반면에, 멀티 프로세싱은 하나의 시스템에서 여러개의 cpu를 사용해 동시에 작업을 처리하는 것이다.
이를 통해 작업 속도를 빠르게 할 수 있다.

 

프로세스끼리 협력하는 방법(IPC: Inter-Process Commnuication)에 대해서 설명해주세요.

  • 프로세스 간의 자원을 공유하고 데이터를 주고받는 것

 

프로세스간 통신 분류

  • 통신 방향
    • 양방향 통신: 데이터를 동시에 양쪽 방향으로 전송
      • ex) 소켓 통신
    • 반양방향 통신: 데이터를 양쪽 방향으로 전송할 수 있지만, 특정 시점에 한족 방향으로만 전송 가능
      • ex) 무전기
    • 단방향 통신: 한쪽 방향으로만 데이터 전송
      • ex) 전역변수와 파이프

 

  • 통신 구현 방식
    • 대기가 있는 통신: 동기화(데이터가 도착했음을 알려주는)를 지원하는 통신 방식
      • 데이터를 받는 쪽은 데이터가 도착할 때까지 자동으로 대기 상태
    • 대기가 없는 통신: 동기화를 지원하지 않는 통신
      • 데이터를 받는 쪽은 바쁜 대기를 사용하여 데이터가 도착했는지 여부를 직접 확인

동작

  • send : 쓰기 연산
  • recieve : 읽기 연산

 

전역 변수를 이용한 통신

    • 공동으로 관리하는 메모리를 사용하여 데이터 주고받기
      • 데이터 전송에는 전역 변수나 파일에 값을 쓴다.
      • 데이터 수신에는 전역변수의 값을 읽는다.
바쁜 대기

 

파일을 이용한 통신

    • 저장장치에 파일을 읽고 쓰기
    • 파일을 열고(open) -> 쓰기(write) 또는 읽기(read) -> 닫는다(close)
바쁜 대기

 

파이프를 이용한 통신

  • 단방향 통신
    • open -> .. -> close
    • 양방향 통신을 하려면 파이프 2개를 사용해야 한다.
    • 운영체제가 제공하는 동기화 통신
  • 연산
    • 데이터 전송: 파이프에 쓰기 연산
    • 데이터 수신: 파이프에 읽기 연산
    • 아직 상대방이 쓰기 연산을 하지 않았다면 대기 상태가 되고, 데이터를 쓰는 순간 동기화가 이루어진다. (바쁜 대기 X)
  • 종류
    • 이름 없는 파이프: 일반적인 파이프, 서로 관련 있는 프로세스간 통신
    • 이름 없는 파이프: FIFO라고 불리는 특수 파일을 이용하며, 서로 관련 없는 프로세스 간 통신에 사용

 

소켓을 이용한 통신

  • 여러 컴퓨터에 있는 프로세스간 통신은 원격 프로시저 호출이나 소켓을 이용한다.
    • 프로시저 호출: 다른 컴퓨터에 있는 함수 호출 (소켓 이용하여 구현)
  • 소켓에 쓰기 연산을 하면 데이터가 전송되고, 읽기 연산을 하면 데이터를 받는다.
  • 양방향 통신이다.

 

스레드(Thread)

스레드에 대해 설명해주세요.

  • 프로세스를 구성하는 실행의 흐름 단위
    • 하나의 프로세스는 여러개의 스레드를 가질 수 있다.
    • 하나의 프로세스가 동시에 여러 일을 처리할 수 있다.
  • 스레드는 프로세스 내에서 각기 다른 스레드 ID, 프로그램 카운터 값을 비롯한 레지스터 값, 스택으로 구성된다.
    • 각 스레드는 고유한 스택을 가지며, 다른 스레드코드, 데이터, 영역을 공유한다.
      • 스레드마다 각기 다른 코드를 실행할 수 있다.
    • 프로세스의 스레드는 실행에 필요한 최소한의 정보만을 유지한 채 프로세스 자원을 공유하며 실행된다.

 

운영체제는 CPU에 처리할 작업을 전달할 때, 프로세스가 아닌 스레드 단위로 전달한다.

스레드 : CPU 스케줄러가 CPU에 전달하는 일
프로세스에는 여러개의 스레드가 존재한다.

 

멀티 스레드

  • 여러 스레드로 프로세스를 동시에 실행하는 것
  • 프로세스 내 작업을 여러개의 스레드로 분할함으로써 작업의 부담을 줄이는 프로세스 운영 기법

 

멀티 프로세스 vs 멀티 스레드

  • 멀티 프로세스: 서로 다른 프로세스는 자원을 공유하지 않고 독립적으로 실행된다.
    • 하나의 프로세스에 문제가 생겨도 다른 프로세스에 영향을 주지 않는다.
  • 멀티 스레드: 프로세스의 자원을 공유하기 때문에 메모리를 효율적으로 사용할 수 있다.
    • 하나의 스레드에 문제가 생기면 다른 스레드도 영향을 받아 프로세스 전체에 문제가 생길 수 있다.

 

스레드의 메모리 공간에 대해 설명해주세요.

  • 같은 프로세스의 모든 스레드는 동일한 주소 공간의 코드, 데이터, 영역과 프로세스 자원을 공유한다.
  • 스레드들은 각기 다른 스레드 ID, 프로그램 카운터 값을 포함한 레지스터 값, 스택을 가진다.

 

스레드 제어블록(TCB)에 대해 설명해주세요.

  • 스레드를 관리하는 자료 구조
    • 스레드 ID, 스레드 상태, CPU 정보, 우선순위, PCB 포인터, 스레드 포인터, 스택 포인터를 가지고 있다.
  • 스레드를 구현하고 관리하는 작업은 유저 영역의 heap에서 한다.
  • 스레드 관련 작업(스케줄링, 실행)등은 커널 영역에서 한다.

 

사용자 수준 스레드커널 수준 스레드의 차이를 설명해 보세요.

    • 스레드는 커널 스레드와 사용자 스레드로 나뉜다.

 

사용자 스레드: 라이브러리에 의해 구현된 일반적인 스레드

  • 사용자 스레드가 커널 스레드를 사용하라면 시스템 호출로 커널 기능을 이용해야 한다.
운영체제가 멀티 스레드를 지원하지 않을 때 사용하였고, 지금은 거의 사용하지 않는다.
  • 커널입장에서는 단일 프로세스이지만, 커널이 하는 일을 라이브러리가 대신 처리하여 여러 스레드가 작동한다.
    • 사용자 프로세스 내에 여러 스레드가 존재하지만, 커널의 스레드 하나와 연결되므로 1 to N 모델이다.
  • 단점
    • 여러 개의 스레드가 하나의 커널 스레드와 연결되므로 커널 스레드가 입출력 작업을 위해 대기할 때, 모든 사용자 스레드가 함께 대기한다.
    • 한 프로세스의 타임 슬라이스를 여러 스레드가 공유하므로 여러 개의 cpu를 동시에 사용할 수 없다.
    • 공유 변수를 보호하는 로직을 직접 라이브러리에서 구현해야하므로 보안에 취약하다.

 

커널 스레드 : 커널이 직접 관리하는 스레드

  • 커널이 멀티스레드를 지원하는 방식
    • 하나의 사용자 스레드가 하나의 커널 스레드와 연결된다 (1 to 1)
    • 커널 스레드는 독립적으로 스케줄링이 되므로, 특정 스레드가 대기 상태에 들어가도 다른 스레드는 작업을 계속할 수 있다.
    • 커널이 제공하는 보호 기능과 같은 모든 기능을 사용할 수 있다.
  • 커널 스레드는 커널 레벨에서 모든 작업을 지원하므로 멀티 CPU를 이용할 수 있다.
  • 하나의 스레드가 대기 상태에 있어도 다른 스레드는 작업을 계속할 수 있다.
  • 커널의 기능을 사용하므로 보안에 강하고 안정적으로 작동한다.
  • 문맥 교환을 할 때 오버헤드 때문에 느리게 작동한다.
    • 사용자 모드-> 커널 모드 : 시스템 호출 필요
    • 사용자 스레드는 모드 전환이 필요 없다.

 

멀티 레벨 스레드

  • 사용자 스레드와 커널 스레드를 혼합한 방식
    • M to N 모델
    • 커널 스레드의 개수가 사용자 스레드보다 같거나 작다.
  • 빠르게 움직여야하는 스레드는 사용자 스레드로, 안정적으로 움직여야하는 스레드는 커널 스레드로 작동한다.

 

멀티 스레드 프로그래밍 대해서 설명해주세요.

  • 여러 프로세스를 생성하는 대신, 코드, 데이터 등을 공유하면서 여러 개의 일을 스레드로 나누어 하나의 프로세스 내에서 하는 것

 

멀티 스레드 프로그래밍의 장단점을 설명해 주세요.

    • 장점
      • 응답성 향상: 한 스레드가 입출력으로 작업이 진행되지 않더라도 다른 스레드가 작업을 계속하여 빨리 응답할 수 있다.
      • 자원 공유: 프로세스가 가진 자원을 모든 스레드가 공유하게 되어 작업을 원활하게 진행할 수 있다.
      • 효율성 향상: 여러 개의 프로세스를 생성하는 것 대신, 멀티 스레드는 불필요한 자원의 중복을 막음으로써 시스템의 효율이 향상된다.
      • 다중 CPU 지원: 다중 CPU가 멀티스레드를 동시에 처리하여 CPU 사용량이 증가하고 프로세스의 처리 시간이 단축된다.
    • 단점
      • 한 스레드에 문제가 생기면 전체 프로세스에 영향을 미친다.
        • 모든 스레드가 자원을 공유하기 때문이다.
크롬은 다른 스레드가 영향을 받는 것을 최소화하기 위해 낭비 요소가 있더라도 멀티태스킹(프로세스 여러개)를 이용한다.
멀티 프로세스는 각 프로세스가 독립적이기 때문에 한 프로세스의 문제가 다른 프로세스로 전달되지 않는다.

 

멀티 프로세스 대신 멀티 스레드를 사용하는 이유가 뭔가요?

  • 멀티 스레드: 프로세스 내 공유가 가능한 부분을 제외하고 실행과 관련된 부분을 스레드로 나누어 관리한다.
    • 자원의 중복 사용을 피함으로써 낭비를 막을 수 있다.
    • 하나의 프로세스에서 여러 스레드를 사용하여 작업의 효율을 높인다.
프로세스간 전환보다 스레드간 전환이 더 빠르다.

 


멀티 스레드 프로그래밍에서 주의할 점이 있을까요?

  • 프로세스 내에서 여러 스레드가 자원을 공유하면서 작업을 하므로 동기화교착상태 문제등을 고려해야한다.
    • 데이터 동기화: 여러 스레드가 같은 데이터 접근시 발생되는 문제
    • 교착 상태: 두 개 이상의 스레드가 서로 점유하는 자원을 기다리며 무한정 대기

 

Thread-Safe하다는 의미와 그렇게 설계하는 방법을 설명해 주세요.

  • 멀티 스레드 프로그래밍에서 여러 스레드가 동시에 같은 코드나 데이터에 적븐해도 프로그램이 의도한 대로 동작하는 특성
    • 멀티 스레드 환경에서 발생할 수 있는 데이터 불일치, 경쟁 조건등의 문제 없이 안전하게 동작하는 것
  • 스레드 안전을 지키기 위한 방법

 

1. 상호 배제 : 한번에 하나의 스레드만 공유 자원에 접근할 수 있도록 하는 방법

public synchronized void increment() {
    count++;
}
성능 저하 발생 가능

2. 원자 연산 : 중간에 끊기지 않고 한번에 완전히 수행되는 연산

private AtomicInteger count = new AtomicInteger(0);
public void increment() {
    count.incrementAndGet();
}
락보다 가볍고 성능이 좋다.

3. 스레드 지역 저장소(Thread-Local Storage) : 각 스레드마다 별도의 저장 공간을 제공하여 데이터를 독립적으로 관리

private ThreadLocal<Integer> threadLocalValue = new ThreadLocal<>();
public void setValue(Integer value) {
    threadLocalValue.set(value);
}
스레드간 동기화가 필요 없어 성능상 좋다.
메모리 누수를 주의해야한다.

4. 재진입성 (Re-Entrancy) : 한 스레드가 획득한 락을 다시 획득한다.

함수가 여러번 호출되거나 중첩되어도 안전하게 작동하는 특성
public synchronized void outerMethod() {
    innerMethod();  // 같은 락을 다시 획득 가능
}
private synchronized void innerMethod() {
}
데드락 방지

 

정리

  • 간단한 동기화 : 상호 배제
  • 성능이 중요할 경우: 원자 연산, 스레드 지역 저장소
  • 복잡한 락 구조: 재진입성

 

728x90