본문 바로가기
OS

1. Introduction to Operating Systems

by 녕인뉸 2022. 10. 6.

1. What happens when a program runs?

(1) 실행 중인 프로그램은 instruction을 실행시킴

  ① Fetch instruction : 프로세서는 메모리로부터 instruction을 가져옴 (fetch)

  ② Decode instruction : 어떤 instruction인지 decode

  ③ Get data : 필요시 operand를 가져옴

  ④ Execute instruction

  ⑤ 프로세서는 다음 instruction 으로 이동

 

2. OS (Operating System)

(1) 컴퓨터 유저와 컴퓨터 하드웨어 사이의 중간 다리 역할을 하는 프로그램

(2) 역할

  - 프로그램이 더 쉽게 run

  - 프로그램이 메모리를 공유

  - 장치와 프로그램이 interact

=> os는 시스템이 정확하고 효율적으로 작동하는지 확인하는 역할

(3) System call : 유저가 OS에게 어떤 서비스를 할건지 알려주는 것을 허용

   - OS는 인터페이스(APIs, standard library)를 제공

   - 전형적인 OS는 많은 시스템 콜을 내보냄 : run programs, access memory, access devices

                                     

(4) The OS is a Resource manager

 - OS는 CPU, 메모리, 디스크와 같은 리소스를 관리

 - 많은 프로그램들이 실행할 때 -> cpu 공유

 - 많은 프로그램들이 동시에 자신의 instruction와 데이터에 접근할 때 -> 메모리 공유

 - 많은 프로그램들이 디바이스에 접근할 때 -> 디스크 공유

 - sharing하기 위해선, OS는 physical resource를 시각화

 

(5) The OS is a Virtual Machine

 - OS는 physical resource를 virtual form으로 변경

 (physical resource: 프로세서, 메모리, 디스크,...)

 - OS를 virtual machine이라고 칭하기도 함

 

(6) Virtualizing the CPU

- 시스템은 많은 vitual CPU를 가짐

 : a single CPU -> a seemingly infinite number of CPUs

 : 많은 프로그램들이 한 번에 실행되는 것처럼 보이도록 허용

 

(7) Virtualizing memory

- physical memory는 바이트 배열

- 프로그램은 메모리의 모든 data structure를 저장

 : Read memory (load) - 데이터에 접근할 수 있도록 address를 명시

 : Write memory (store) - 주어진 address에 쓸 수 있는 데이터 명시

 

//mem.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "common.h"

int main(int argc, char *argv[])
{
    int *p = malloc(sizeof(int)); // a1: allocate memory
    assert(p != NULL);
    printf("(%d) address of p: %08x\n", getpid(), (unsigned) p); // a2: print out the address of the memory
    *p = 0; // a3: put zero into the first slot of the memory
    while (1) {
        Spin(1);
        *p = *p + 1;
        printf("(%d) p: %d\n", getpid(), *p); // a4
    }
    return 0;
}

int형 포인터를 malloc으로 메모리를 할당

*p = 0; -> 메모리의 첫 슬롯에 0을 넣음

반복문을 돌면서 포인트를 1씩 증가시킨 후 현재 pid와 포인터가 가리키는 값을 출력

 

새롭게 할당된 메모리의 주소는 00200000

p의 값을 업데이트하면서 출력

 

 

- mem.c를 여러 번 실행

> 실행 중인 프로그램이 own private memory를 갖고 있는 것과 같음

  : 실행 중인 프로그램은 같은 주소에서 메모리를 할당

  : 독립적으로 00200000에 값을 업데이트

 

(8) Virtual address space

- 각 프로세스는 자신 소유의 virtual address space (VAS)에 접근

 : OS는 virtual address space를 physical memory에 맵핑

 : 하나의 실행 중인 프로그램의 메모리 reference는 다른 프로세스의 address space에 영향을 주지 않음

 : Physical memory는 공유된 리소스이며 os에 의해 관리

 

(9) The problen of concurrency (많은 core)

- OS는 한 번에 많은 일을 저글링하여, 순차적으로 프로세스를 수행

- 현대 multi-thread 프로그램도 concurrency 문제를 나타내고 있음

 : multi-thread는 동시에 수행할 수 있는 프로세스 내의 control flow (하나의 프로세스 메모리를 공유하면 race condition 문제 발생)

#include <stdio.h>
#include <stdlib.h>
#include "common.h"

volatile int counter = 0; int loops;
 
void *worker(void *arg) { // 입력 받은 loop만큼 반복문을 돌면서 counter 증가
    int i;
    for (i = 0; i < loops; i++) counter++;
    return NULL;
}
 
int main(int argc, char *argv[]) {
    if (argc != 2) {
    fprintf(stderr, "usage: threads <value>\n"); exit(1);
    }
    loops = atoi(argv[1]);
    pthread_t p1, p2;
    printf("Initial value : %d\n", counter);

    Pthread_create(&p1, NULL, worker, NULL);
    Pthread_create(&p2, NULL, worker, NULL);
    Pthread_join(p1, NULL);
    Pthread_join(p2, NULL);
    printf("Final value : %d\n", counter);
    return 0;
}

loops : 2개의 worker가 loop 안에서 몇 번이나 공유된 counter를 증가시킬 건지를 결정

loops == 1000

loops == 1000000

프로세스가 virtualize되면서 중간중간 switching이 일어남

-> update된 값이 아니라 예전 값으로 수행하므로 원하는 결과가 나오지 않음

 

**Why is this happening?

- 공유된 counter를 증가 (counter++) -> 3개의 instruction을 수행

(1) 메모리에서 레지스터로 counter의 값을 load (reg <- mem)

(2) 레지스터를 증가 (reg <- reg + 1)

(3) 이를 메모리에 다시 저장 (mem <- reg)

 

- 이 3개의 instruction은 atomical(원자적으로)하게 수행되지 않음 => concurrency 문제 발생

(atomical : 동시에 이뤄지지 않는다는 건가?)

 

-> OS는 이 문제를 해결할 수 있는 메카니즘을 제공

 

(10) Persistence

- DRAM과 같은 장치들은 휘발성 방식으로 value를 저장

- 하드웨어와 소프트웨어는 데이터를 영구적으로 저장할 때 사용됨

 : 하드웨어 - 하드드라이브, solid-state 드라이브 (SSDs)와 같은 I/O 장치

 : 소프트웨어 - 파일 시스템은 디스크를 관리, 유저가 생성한 모든 파일을 시스템 디스크에 안정적이고 효율적인 방식으로 저장

- CPU나 메모리와 달리, OS는 각 애플리케이션에 대해 가상화된 개인 디스크를 생성하지 않음

- 오히려 유저가 파일 안에 있는 정보를 공유하고 싶어할 것이라고 가정 (?)

 

 

//tmp.c -> hello world
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
    int fd = open("/tmp/file", O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
    assert(fd > -1); // fd > -1이면 true(1)이 나와서 ㄱㅊ, 그렇지 않으면 assert error
    int rc = write(fd, "hello world\n", 13);
    assert(rc == 13);
    close(fd);
    return 0;
}

open, write, close 시스템 콜은 요청을 처리하는 파일 시스템이라고 불리는 OS의 영역으로 라우팅됨

 

- OS는 디스크에 write하기 위해 무엇을 할까?

 : 새로운 데이터가 디스크의 어디에 상주할 것인지 파악

 :  디바이스 드라이버를 사용하여 저장 디바이스에 I/O 요청을 발행

 

- 파일 시스템은 write하는 동안 시스템 충돌을 처리

 :  journaling / copy-on-write

 : 디스크에 write 순서를 신중하게 지정하여, write 시퀀스 중에 오류가 발생하면 시스템이 적절한 상태로 복구할 수 있음

 

**조각 모임(?) -> sequential

 

(11) OS design goals

- 추상화 구축 : 시스템을 편리하고 쉽게 사용하도록

- 높은 성능 제공 : OS의 오버헤드를 최소화하고, OS는 과도한 오버헤드 없이 virtualization을 제공해야함

- 애플리케이션 간의 보호

 : Isolation - 한 프로세스에 의해 발생하는 나쁜 수행은 다른 프로세스와 OS에 영향을 주지 않음

- 높은 수준의 신뢰성 : OS는 non-stop으로 실행돼야 함

- 다른 이슈 : 에너지 효율성, 보안, 이동성

 

'OS' 카테고리의 다른 글

6. Scheduling : The Multi-level feedback Queue  (0) 2022.10.14
5. Scheduling : Introduction  (0) 2022.10.14
4. Mechanism: Limited Direct Execution  (0) 2022.10.13
3. Process API  (0) 2022.10.09
2. The Abstraction : The Process  (0) 2022.10.09