관리 메뉴

코딩하는 락커

11. 프로세스 동기화: Chapter 6. Synchronization Tools (Part 1) 본문

📀 운영체제

11. 프로세스 동기화: Chapter 6. Synchronization Tools (Part 1)

락꿈사 2022. 6. 6. 19:02

6.1 배경Background

  • 프로세스가 병행concurrent 또는 병렬parallel로 실행될 때 여러 프로세스가 공유하는 데이터의 무결성에 문제가 생길 수 있음 
  • 생산자-소비자 문제
    • 생산자: 버퍼에 새 항목을 초기화 할 때 마다 0으로 초기화 되어 있는 count 값을 1 증가함
    • 소비자: 버퍼에서 한 항목을 꺼낼 때마다 0으로 초기화 되어 있는 count값을 -1 감소함

생산자 코드
소비자 코드

  • 병행으로 수행할 경우 count의 값은 4나 5나 6이 됨
  • 실습 예제1 코드
#include <stdio.h>
#include <pthread.h>

int sum = 0;

void *run(void * param){
    int i;
    for (i=0; i<10000; i++){
        sum++;
    }
    pthread_exit(0);
}

int main(){
    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, run, NULL);
    pthread_create(&tid2, NULL, run, NULL);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    printf("%d\n", sum);
}

  • 실습 예제 2 코드
#include <stdio.h>
#include <pthread.h>

int sum = 0;

void *run1(void *param){
    int i;
    for (i=0; i<10000; i++){
        sum++;
    }
    pthread_exit(0);
}

void *run2(void *param){
    int i;
    for (i=0; i<10000; i++){
        sum--;
    }
    pthread_exit(0);
}

int main(){
    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, run1, NULL);
    pthread_create(&tid2, NULL, run2, NULL);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    printf("%d\n", sum);
}

  • 원인
    • count ++의 기계어 구현
      • register1 = count
      • register1 = register1 +1
      • count = register1
    • count --의 기계어 구현
      • register2 = count
      • register2 = register2 +1
      • count = 
    • register1, register2는 한 CPU만 접근할 수 있는 레지스터 중 하나임
    • register1, register2가 동일하 물리적 레지스터더라도 이 레지스터의 내용은 인터럽트 처리기에 의해 메모리에 보관되었다가 다시 적재
    • 따라서 아래 그림과 같은 순서를 가질 수 있음

  • 이러한 부정확한 상태에 도달하는 것은 두 개의 프로세스가 동시에 변수 count를 조작하도록 허용했기 때문임
  • 경쟁 상황race condition: 동시에 여러 개의 프로세스가 동일한 자료를 접근하여 조작하고, 그 실행 결과가 접근이 발생한 특정 순서에 의존하는 상황
  • 한 순간에 한 프로세스만이 변수 count를 조작하도록 보장하기 위해 프로세스들이 동기화synchronized되도록 할 필요가 있음
  • Race Condition Java 예제 코드
package com.os_study.ch04;

class RunnalbeTwo implements Runnable{
    static int count = 0;

    @Override
    public void run() {
        for(int i=0; i<10000; i++){
            count++;
        }
    }
}

public class RaceCondition2 {
    public static void main(String[] args) throws Exception{
        RunnalbeTwo run1 = new RunnalbeTwo();
        RunnalbeTwo run2 = new RunnalbeTwo();
        Thread t1 = new Thread(run1);
        Thread t2 = new Thread(run2);
        t1.start(); t2.start();
        t1.join(); t2.join();
        System.out.println("Result: " + RunnalbeTwo.count);
    }
}

 

 

6.2 임계구역 문제 The Critical Section Problem

  • 임계구역critical section: 하나 이상의 다른 프로세스와 공유하는 데이터를 접근하고 갱신하는 코드 영역
  • 한 프로세스가 자신의 임계구역에서 수행하는 동안 다른 프로세스들은 그들의 임계구역에 들어올 수 없음
  • 임계구역 문제
    • 프로세스들이 데이터를 협력적으로 공유하기 위하여 자신들의 활동을 동기화할 때 사용할 수 있는 프로토콜을 설계하는 것
  • 진입 구역entry section: 임계구역으로 진입하기 위해 진입 허가를 요청하는 부분
  • 퇴출 구역exit section: 임계구역 뒤에 나오는 부분, 후처리를 해줌
  • 나머지 구역remainder section: 코드의 나머지 부분을 총칭
  • 임계구역 문제에 대한 해결안의 3가지 요구조건
    1. 상호 배제mutual exclusion: 프로세스가 Pi가 자기의 임계구역에서 실행된다면 다른 프로세스들은 그들 자신의 임계구역에서 실행될 수 없음
    2. 진행progress: 자신의 임계구역에서 실행되는 프로세스가 없고 그들 자신의 임계구역으로 진입하려고 하는 프로세스들이 있다면 다음에 누가 임계구역으로 진입할 수 있는지를 결정하는지에 대한 선택은 무한정 연기될 수 없음
    3. 한정된 대기bounded waiting: 프로세스가 자기의 임계구역에 진입하려는 요청을 한 후부터 그 요청이 허용될 때 까지 다른 프로세스들이 그들 자신의 임계구역에 진입하도록 허용되는 회수에 한계가 있어야 함
  •  많은 커널 모드 프로세스들이 동시에 운영체제 안에서 활성화될 수 있으므로 운영체제를 구현하는 코드(커널 코드)는 경쟁 조건이 발생하기 쉬움

  • 위 그림은 P0, P1 두 프로세스가 fork() 시스템 콜을 사용하여 자식 프로세스를 생성하는 예시를 나타냄
    • fork()는 새로 생성된 프로세스의 프로세스 식별자를 부모 프로세스로 변환함
    • 이 예시에서 커널변수 next_available_pid는 다음 사용 가능한 프로세스 식별자의 값을 나타내며 경쟁 조건에 있음
    • 상호 배제가 제공되지 않으면 동일한 프로세스 식별자 번호가 두 개의 다른 프로세스에 배정될 수 있음
  • 단일 코어 환경에서는 공유 변수를 수정하는 동인 인터럽트가 발생하는 것을 막으면 임계구역 문제를 해결할 수 있음
    • 멀티 코어 환경에서 실현할 수 없음
      • 메시지가 모든 프로세서에 전달되므로 인터럽트를 비활성화 하면 시간이 많이 걸림
      • 또한 이 메시지 전달은 각 임계구역으로의 진입을 지연시키고 시스템 효율성을 떨어뜨림
  • 운영체제에서 임계구역 문제를 다루기 위한 2가지 접근법
    1. 선점형 커널
      • 프로세스가 커널 모드에서 수행되는 동안 선점되는 것을 허용
      • 커널 모든 프로세스가 대기 중인 프로세스에 처리기를 양도하기 전에 오랫동안 실행할 위험이 적기 
        때문에 응답이 더 민첩하므로 선점형 커널을 선호함
    2. 비선점형 커널
      • 프로세스가 커널 모드에서 수행되는 동안 선점되는 것을 허용하지 않음
      • 한 순간에 커널 안에서 실행중인 프로세스는 하나밖에 없으므로 경쟁 조건을 염려할 필요 없음

 

 

 

 

Comments