Hi there!

I am a student studying computer science.

시스템 프로그래밍

시스템 프로그래밍 2장 - Library call : File I/O

만능성구 2020. 5. 5. 03:20
728x90

Standard I/O Library

<stdio.h>

- File I/O와 관련된 Library가 define된 header file

- fopen fclose fread fwrite fflush fgetc 등이 들어있다.

I/O stream object

- <stdio.h>를 이용해서 standard I/O Library를 이용해서 프로그래밍하면 그 대상이 되는 객체

- 대문자 FILE* 포인터 형태로 넘겨받는다.

- 대상이 되는 파일에 대해서 I/O를 수행할 수 있게 된다.

- file에 대한 유용한 시스템 정보들을 가지고 있는 객체이다.

특별히 shell에 대해서는 객체 3개를 제공한다.

stdin 표준 입력, stdout 표준 출력, stderr 표준 에러

File I/O 방식 - Library call / System call

  • Library call : file io stream object인 FILE*을 이용
  • system call : file descriptor를 이용 // file descriptor : 파일에 할당되는 숫자(id)

library도 결국 system call을 부른다 ex ) printf, fprintf, puts, write

Why use libray?

- 훨씬 편리하다

- formmting되어 있다

- user level buffering 사용

Library call & System call를 같이 쓰면 ?

하나에 파일에 대한 File stream, File Descriptor가 동일하게 존재해야한다.

1대 1 mapping된다.

#include <stdio.h>

int fileno(FILE *stream);

file stream object로 파일 descriptor를 반환
#include<stdio.h>

FILE *fdopen(int fildes, const char *mode);

descriptor로 file stream object를 반환

Library buffering

buffer란?

: 데이터를 임시 저장할 수 있는 메모리공간

- Library buffer는 file pointer object를 이용해서 file을 open해서 data를 write하기 전에 임시저장할 수 있는 공간(buffer) 마련하고 그 공간에 저장한 다음 buffer에 data를 모아서 한번에 write한다.

- 실제 Libraray call에 비해 System call을 호출하는 횟수가 줄어든다.

(실제로 file을 write하기 위해서 kernel에 write 요청을 해서 kernel을 통해서 data를 write하는데 system call을 해주어야하니깐 모아서 한번에 write한다.)

Buffering 방식

  1. Full buffering
    - buffer의 크기를 크게 잡고 (디스크의 몇 개의 block 4kb, 8kb ) 프로그램 효율성을 높인다.
    - I/O에 해당하는 크기만큼 buffer를 가진다.
    - fflush()를 이용해서 buffer를 가득 안채우고 data를 뺀다.
  2. Line buffering
    - consol에서 주로 사용한다.
    - 프로그램에서도 getchar()를 사용하면 사용된다.
    - enter가 입력될 때까지 buffer가 쌓인다.
    - enter가 입력되기 전에 프로그램이 다운되면 data를 잃어버린다.
    - 그래도 메모리 낭비가 적다
  3. Unbuffering
    - buffering을 하지 않는 것
    - Memory에 대한 낭비는 없지만 data를 쓸 때마다 system call 발생해서 성능이 좋지 않다.
    - data는 안전하다

Linux library는

stderr: always unbuffering

stdin/ stdout : line buffering

그 이외에는 : full bufferibng

Set buffering type

buffer에 대한 설정하는 두 함수.

buffer를 설정하지 않아도 내부적으로 사용하긴 하지만 이런 두 함수를 이용해서 버퍼 포인터를 제공한다.

#include < stdio.h>

void setbuf(FILE *stream, char *buf);

buffer 영역을 지정하는 함수

buf : non_NULL address for normal buffering, NULL if unbuffering

return : None

#include < stdio.h>

int setvbuf(FILE *stream, cahr *buf, int type, size_t size);

buffer 영역 + type, size를 지정

buf : non_NULL address for normal buffering, NULL if unbuffering

type:  _IOFBF : Full buffering / IOLBF : Line buffering / _IONBF : Unbuffering

size_t : 크기

return : 0  /  non zero

Kernel Buffering

- OS 내의 kernel에서도 data를 모아서 처리하도록 구현되어있다.
- user level의 buffer와는 별도이다.

-disk I/O(disk file)에 대해서 stroge I/O에 대한 횟수를 줄이기 위해서 buffeing의 개념을 사용한다.

buffer cache

- buffer는 한방향으로 모아서 한번에 전달하지만 cache는 중간 매개체 역할한다.

- I/O읽거나 쓸 때 data가 있나 없나 확인한다. // cache가 buffing 역할까지 같이 한다.

- 그런데 Linux kernel에는 I/O를 위한 page cache라는 buffer가 있다. // buffer cache와 연관이 되게 되어있다.

- 일반적으로 buffer cache가 존재하고 많은 user에 대한 system call I/O가 왔을 경우 buffer cache에 모아서 주기적으로 disk같은 stroge에 data를 쓴다.

- stroge에서 data를 읽었을 때에도 buffer cache에 올라온 다음 user에게 전달된다.

-일반적으로I/O에 대한 system call이 buffer cache를 통해서 전달 받게 된다. system call이 library call에 의해서 불려져서 user level에서는 double buffering이 걸린다.

kernel buffer는 library와 큰 상관은 없지만 OS 내부에서 데이터 I/O할 때 전달되는지 개념적인 설명

fflush(...)

buffing된 것을 가득차지 않았을 때도 실제 매체에 쓰게 해주는 것

#include <stdio.h>

int fflush(FILE *stram);

library buffer에 있는 것을 kernel레벨로 내려준다.

return 0 / EOF

z.B)

```

printf(“something”);

fflush(stdout);

```

만약에 disk에 data를 쓰는 operation을 사용했을 때 library call로 user레벨에서 kernel까지만 내려간다. 그런데 sync()까지 불려주면 disk까지 들어간다.

전체 그림에서 printf() fput()는 buffer를 쓰고 fflush(..) 로 library buffer에서 system call로 kernel에 보냈다.

kenel에서 disk같은 비휘발성 Memory에 쓰려면 fsync() 나 sync()를 실행한다.

if 바로 쓰려면 buffer를 없애setbuf(stream,NULL)버리고 파일을 열 때 open(path, flag | O_SYNC, mode) sync옵션을 사용한다.

728x90