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 방식
- Full buffering
- buffer의 크기를 크게 잡고 (디스크의 몇 개의 block 4kb, 8kb ) 프로그램 효율성을 높인다.
- I/O에 해당하는 크기만큼 buffer를 가진다.
- fflush()를 이용해서 buffer를 가득 안채우고 data를 뺀다. - Line buffering
- consol에서 주로 사용한다.
- 프로그램에서도 getchar()를 사용하면 사용된다.
- enter가 입력될 때까지 buffer가 쌓인다.
- enter가 입력되기 전에 프로그램이 다운되면 data를 잃어버린다.
- 그래도 메모리 낭비가 적다 - 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옵션을 사용한다.
'시스템 프로그래밍' 카테고리의 다른 글
시스템 프로그래밍 3장 - System call (0) | 2020.05.05 |
---|---|
시스템 프로그래밍 2장 - Library call : File I/O function (0) | 2020.05.05 |
시스템 프로그래밍 2장 - Library call (0) | 2020.05.05 |
시스템 프로그래밍 1장 - Shell, File system, Compile (0) | 2020.05.05 |
시스템 프로그래밍 1장 - System-call, Library-call (0) | 2020.05.05 |