본문 바로가기
우테코 자유테크 스터디/쉽게 배우는 운영체제

[OS] Ch.5 프로세스 동기화

by ♡˖GYURI˖♡ 2024. 2. 22.

1. 프로세스 간 통신

1. 프로세스 간 통신의 개념

프로세스는 시스템 내에서 독립적으로 실행되기도 하고 데이터를 주고받으며 협업하기도 함

프로세스가 다른 프로세스와 데이터를 주고받는 프로세스 간 통신(IPC)에는 같은 컴퓨터 내에 있는 프로세스뿐만 아니라 네트워크로 연결된 다른 컴퓨터에 있는 프로세스와의 통신도 포함됨

 

프로세스 간 통신의 종류

  • 프로세스 내부 데이터 통신 : 하나의 프로세스 내에 2개 이상의 스레드가 존재하는 경우의 통신이다. 프로세스 내부의 스레드는 전역 변수나 파일을 이용하여 데이터를 주고 받는다.
  • 프로세스 간 데이터 통신 : 같은 컴퓨터에 있는 여러 프로세스끼리 통신하는 경우로, 공용 파일 또는 운영체제가 제공하는 파이프를 사용하여 통신한다.
  • 네트워크를 이용한 데이터 통신 : 여러 컴퓨터가 네트워크로 연결되어 있을 때도 통신이 가능한데, 이 경우 프로세스는 소켓을 이용하여 테이터를 주고받는다. 이처럼 소켓을 이용하는 프로세스 간 통신을 네트워킹이라고 한다. 다른 컴퓨터에 있는 함수를 호출하여 통신하는 원격 프로시저 호출도 여기에 해당한다.

 

2. 프로세스 간 통신의 분류

2.1 통신 방향에 따른 분류

양방향 통신 데이터를 동시에 양쪽 방향으로 전송할 수 있는 구조로, 일반적인 통신은 모두 양방향 통신이다. 프로세스 간 통신에서는 소켓 통신이 양방향 통신에 해당한다.
반양방향 통신 데이터를 양쪽 방향으로 전송할 수 있지만 동시 전송은 불가능하고 특정 시점에 한쪽 방향으로만 전송할 수 있는 구조이다. 반양방향 통신의 대표적인 예는 무전기이다.
단방향 통신 모스 신호처럼 한쪽 방향으로만 데이터를 전송할 수 있는 구조이다. 프로세스 간 통신에서는 전역 변수와 파이프가 단방향 통신에 해당한다.

 

2.2 통신 구현 방식에 따른 분류

대기가 있는 통신 동기화를 지원하는 통신 방식이다. 데이터를 받는 쪽은 데이터가 도착할 때까지 자동으로 대기 상태에 머물러 있는다.
대기가 없는 통신 동기화를 지원하지 않는 통신 방식이다. 데이터를 받는 쪽은 바쁜 대기를 사용하여 데이터가 도착했는지 여부를 직접 확인한다.

 

*동기화 : 데이터가 도착했음을 알려주는 것

 

프로세스 간 통신의 분류

분류 방식 종류
통신 방향에 따른 분류 양방향 통신 일반적 통신, 소켓
반양방향 통신 무전기
단방향 통신 전역 변수, 파일, 파이프
통신 구현 방식에 따른 분류 대기가 있는 통신(동기화 통신) 파이프, 소켓
대기가 없는 통신(비동기화 통신) 전역 변수, 파일

 

 

3. 프로세스 간 통신의 종류

3.1 전역 변수를 이용한 통신

  • 공동으로 관리하는 메모리를 사용하여 데이터를 주고 받는 것
  • 주로 직접적으로 관련이 있는 프로셋 간에 사용
  • 서로 연관이 없는 프로세스 간 통신에도 exterm 변수와 같은 전역 변수 사용 가능

 

3.2 파일을 이용한 통신

  • 파일 열기
    • open("파일.txt", O_RDWR) : fd(파일 기술자) 반환
    • fd : 해당 파일에 접근할 수 있는 일종의 열쇠
  • 읽기 또는 쓰기 연산
    • write(fd, "Test", 5)
    • read(fd, buf, 5)
  • 파일 닫기
    • close(fd)

 

  • 동기화 X → 부모 프로세스가 wait() 함수 사용

 

3.3 파이프를 이용한 통신

  • 파이프는 단방향이기에 양방향 통신을 하려면 파이프르 2개 사용해야 함

종류

  • 이름 없는 파이프 : 일반적인 파이프, 서로 관련 있는 프로세스 간 통신에 사용
  • 이름 있는 파이프 : FIFO라 불리는 특수 파일을 이용하며 서로 관련 없는 프로세스 간 통신에 사용

 

3.4 소켓을 이용한 통신

네트워킹 : 여러 컴퓨터에 있는 프로세스 간 통신

  • IP(Internet Protocol)
    • 목적지까지 데이터를 전송하는 것
    • IP 주소는 목적지를 나타냄
  • 포트(Port)
    • 하나의 컴퓨터 내에서 네트워크를 사용하는 각 프로세스를 구분하는 주소
    • TCP가 네트워크를 사용하는 프로세스를 구분하기 위해 사용하는 주소
  • 데몬(Daemon)
    • 서버에서 돌아가는 프로세스
    • 서버용 데몬도 포트 번호가 필요
      • 클라이언트가 해당 번호를 매번 찾아야하는데, 이러한 수고를 덜기 위해 중요한 데몬은 미리 정해진 포트 번호를 할당함 (e.g. Http 데몬 : 80, Https 데몬 : 443)

 

3.5 정리

종류 운영체제 동기화 지원 open()/close() 사용
전역 변수 X (바쁜 대기) X
파일 X (wait() 함수 이용) O
파이프 O O
소켓 O O

 

 

2. 공유 자원과 임계구역

1. 공유 자원의 접근

공유 자원

여러 프로세스가 공동으로 이용하는 변수, 메모리, 파일 등

 

경쟁 조건

  • 2개 이상의 프로세스가 공유 자원을 병행적으로 읽거나 쓰는 상황
  • 공유 자원 접근 순서에 따라 실행 결과가 달라질 수 있음

 

2. 임계 구역

  • 공유 자원 접근 순서에 따라 실행 결과가 달라지는 프로그램의 영역
  • 임계구역에서는 프로세스들이 동시에 작업하면 안 됨

 

3. 생산자-소비자 문제

생산자 프로세스와 소비자 프로세스가 서로 독립적으로 작업하면서 발생하는 문제

  • 동시 실행 시 문제 발생
  • 생산자와 소비자가 전역 변수 sum에 접근하는 타이밍을 서로 맞추지 않았기 때문
  • 하드웨어에서도 일어나는 문제 (ex. 프린터)

 

4. 임계구역 해결 조건

  • 상호 배제 : 한 프로세스가 임계구역에 들어가면 다른 프로세스는 임계구역에 들어갈 수 없다.
  • 한정 대기 : 어떤 프로세스도 무한 대기하지 않아야 함
  • 진행의 융통성 : 한 프로세스가 다른 프로세스의 진행을 방해해서는 안 됨

 

3. 임계구역 해결 방법

1. 기본 코드 소개

#include <stdio.h>

typedef enum {false, true} boolean;
extern boolean lock = false;
extern int balance;

main() {
    while(lock == true);
    lock = true;
    balance = balance + 10;
    lock = false;
}

 

 

2. 임계구역 해결 조건을 고려한 코드 설계

2.1 상호 배제 문제

  • lock == true 인 경우 무한 루프 돌면서 대기
  • lock == false인 경우 lock을 걸고 임계구역에서 작업한 후 lock을 해제하고 나옴

 

문제점

  • lock == false일 때, lock = true로 걸고 임계구역에 진입해야 하는데 그 직전에 타임아웃이 걸린다면?
    • 다른 프로세스도 임계구역에 진입하게 되고, 해당 타임아웃으로 대기하고 있던 프로세스도 대기가 끝나 실행될 대 또 임계구역에 진입해버림
    • 동시에 임계구역에 진입할 수 있음

 

2.2 한정 대기 문제

  • 상호 배제 조건은 만족하지만, 타임아웃 타이밍에 따라 상호 무한루프에 빠질 수 있는 위험이 있음

 

2.3 진행의 융통성 문제

  • 상호 배제와 한정 대기 조건 만족
  • 만약 P1이 자주 실행되어야 하는 상황이라면?
    • P1과 P2는 서로 번갈아가며 실행되어야 하기에 진행의 융통성 조건을 보장하지 못함

 

2.4 하드웨어적인 해결 방법

 

3. 피터슨 알고리즘

 

  • 임계구역 해결의 세 가지 조건 모두 만족
  • 2개의 프로세스만 사용 가능하다는 한계

 

4. 데커 알고리즘

  • 임계구역 해결의 세 가지 조건 모두 만족
  • 2개의 프로세스만 사용 가능하다는 한계

 

5. 세마포어

프로세스가 작업을 마치면 다음 프로세스에 임계구역을 사용하라는 동기화 신호를 보냄

  • Semaphore(n) : 전역변수 RS를 n으로 초기화, n은 현재 사용 가능한 자원의 수
  • P() : 잠금을 수행하는 코드
    • RS>0이면 (사용 가능한 자원이 있으면) : RS를 1만큼 감소시키고 임계구역 진입
    • RS≤0이면 : 0보다 커질 때 까지 block()
  • V() : 잠금 해제와 동기화를 같이 수행
    • RS 값을 1 증가시킴
    • 세마포어에서 기다리는 다른 프로세스에게 wake_up() 신호를 보내 임계구역에 진입해도 좋다는 신호 보냄

 

BINARY SEMAPHORE

  • 초기값이 1
  • 상호 배제를 위해 사용 (하나 들어가면 아무도 못들어감)

 

COUNTING SEMAPHORE

  • 초기값이 1 이상
  • 한 개 이상의 자원이 있을 때 사용
  • 여러 개의 프로세스가 임계구역에 접근 가능

 

세마포어의 잘못된 사용 예

 

6. 모니터

  • 공유 자원을 내부적으로 숨기고 공유 자원에 접근하기 위한 인터페이스만 제공
  • 자원을 보호하고 프로세스 간에 동기화를 시킴

  • 임계구역으로 들어가려는 프로세스는 직접 P() 혹은 V()를 사용하지 않음
  • 대신 모니터에게 작업을 요청
  • 모니터는 요청받은 작업을 모니터 큐에 저장하고 순서대로 처리, 결과만 프로세스에 알려줌

 

 

4. 파일, 파이프, 소켓 프로그래밍

1. 파일

1.1 순차 파일

  • 파일 내 데이터가 한 줄로 길게 저장
  • ex. 카세트 테이프

 

1.2 파일 기술자(fd)

  • 현재 파일에서 어느 위치를 읽고 있는지 가리킴
  • 해당 파일에 접근할 수 있는 권한
  • 처음에는 파일 맨 앞에 위치
  • 파일을 읽거나 쓰면 파일 기술자는 전진함

 

1.3 파일을 이용한 통신

  • 부모 프로세스가 자식 프로세스보다 먼저 실행되면 자식 프로세스가 아무 작업도 하지 않으므로 빈 내용을 읽게 됨
    • 따라서 부모-자식 프로세스 간 동기화 필수
    • 부모 프로세스는 wait() 함수를 통해 자식 프로세스가 끝나기를 기다림
  • fork() 이전에 파일을 open()하면 생성된 fd가 자식 프로세스에도 상속됨
    • 자식 프로세스도 파일 접근 가능
    • 한 fd를 공유함
    • open() 1번 close() 두 번
  • 자식 프로세스가 작업이 끝나면 lseek()을 통해 fd를 맨 앞으로 보냄
  • 동기화 X
    • 파일에서는 fd를 공유하므로 read(), write() 상관 없이 fd가 전진하므로 동기화 불가

 

2. 파이프

  • 부모-자식과 같이 서로 연관된 프로세스 통신에 사용
  • read(), write()의 기술자가 따로 존재함
  • fork() 발생 시 총 4개의 기술자 존재
  • 단방향 통신이므로 프로세스당 1개의 기술자만 사용
    • 필요없는 기술자는 닫아버림
  • 대기가 있는 통신이므로 wait()가 필요 X
    • 부모 프로세스가 먼저 실행되면 파이프에 메시지가 들어올 때 까지 대기상태

 

3. 네트워킹

  • 클라이언트 통신 절차
    1. 클라이언트는 소켓을 생성하고 connect() 를 사용하여 서버와의 접속 시도
    2. 서버와 접속되면 read()/write() 작업 수행
    3. 작업이 끝나면 사용한 소켓 기술자를 닫고 종료
  • 서버 통신 절차
    1. 서버는 소켓을 생성하고 bind()를 사용하여 생성한 소켓을 특정 포트에 등록 (하나의 포트에 여러 개의 소켓을 생성)
    2. 소켓이 정상적으로 등록되면 listen() 을 실행하여 클라이언트를 받을 준비를 함
    3. 클라이언트를 받으면 accept() 를 실행하여 소켓 기술자를 생성 후 작업 수행
  •