파일 입출력

Jongwon·2021년 12월 6일
0

Linux Programming

목록 보기
11/25

파일 입출력 함수들은 응용 프로그램이 시스템 호출을 통해 직접적으로 운영체제에 서비스를 받도록 한다. 파일 입출력 함수에서 데이터는 page cache를 통해 큰 단위로 read와 write를 한다.
man page의 (2)라고 표시된 함수들은 모두 System Call 함수이고, 운영체제의 시스템 콜 인터페이스에 정의가 되어있다.

Page Cache(Buffer Cache)

보조기억장치와 메인 메모리 사이의 속도차를 줄이기 위해 개발, 동적인 크기 지원

교체정책 : 캐시 가득 찼을 때 교체할 메모리

  • FIFO
  • RANDOM
  • LRU(Least Recently Used)
  • LFU(Least Frequently Used)

hit ratio = cache hit count / total reference count, 높을수록 좋다.
read ahead : 앞으로 접근이 예상되는 자원을 미리 읽어둠.

Locality of Reference

일부 자원의 참조확률이 올라가는 것

  • Spatial Locality : 현재 자원과 인접한 곳에서 참조 발생 확률 높음
  • Temporal Locality : 특정 시점에서 자원에 접근 시, 다시 참조될 확률 높음

page writeback : page cache에 있는 쓰일 내용을 보조기억장치에 한번에 작성

  • page cache 여유메모리 부족하거나, 일정 시간이 지나면 write함
  • 위의 상황 발생 시 pdflush 동작



<fcntl.h> 헤더

  • int open(const char *pathname, int open_flag, [mode_t mode])
    file descriptor 번호 반환
open_flag
기본: O_RDONLY, O_WRONLY, O_RDWR
추가: O_APPEND, O_CREAT, O_DIRECT, O_EXCL, O_DIRECT, O_TRUNC, O_NONBLOCK, O_SYNC
O_DIRECT : 캐시에 저장안하고 바로 I/O
O_EXCL : 파일 생성 시 파일명 있으면 에러 반환
O_SYNC : 쓰기 연산마다 디스크 I/O 발생
mode_t mode
쓰기 실행 시, 권한 설정
  • int creat(const char *pathname, mode_t mode)
    open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode)와 동일


<unistd.h> 헤더

  • int close(int filedes)
    -1이면 에러, 0이면 성공
    ssize_t read(int filedes, void *buf, size_t nbytes)
    읽은 byte수 반환, nbytes보다 작으면 시그널에 의한 중단 or 파일끝, 반환안되면 프로세스 중단 후 대기중,
void *buf
읽은 데이터 저장할 버퍼
size_t nbytes
읽어들일 최대 byte 수)
  • ssize_t write(int filedes, const void *buf, size_t nbytes)
    정상 시 nbytes 반환(buf가 부족하면 NULL로 채움)
const void *buf
쓰기 위해 읽을 데이터 
  • off_t lseek(int filedes, off_t offset, int whence)
    파일의 새로운 offset 반환
off_t offset
whence 기준 상대적 거리
whence 
기준점: SEEK_END, SEEK_CUR, SEEK_SET

음수면 0으로 바꿔주고, 파일크기 넘기면 쓸 때 커짐
  • ssize_t pread(int fd, void *buf, size_t count, off_t pos)

  • ssize_t pwrite(int fd, void *buf, size_t count, off_t pos)
    읽고 쓸 시작위치 지정하여 멀티쓰레드 지원, 그 외는 read(), write()와 같다

  • int fsync(int fd) 버퍼에 수정사항(메타데이터 포함)을 디스크에 저장

  • int fdatasync(int fd) 파일데이터만 바로 저장

  • void sync(void) 모든 변경을 적음

  • int ftruncate(int fd, off_t len)

  • int truncate(const chat* path, off_t len)
    len길이 이후의 파일을 자르고, 0이면 성공, -1이면 실패

둘의 차이 : truncate는 open할 필요가 없음
  • int dup(int fd) 사용하지 않는 가장 작은 fd의 엔트리 할당
  • int dup2(int fd, int newfd) newfd로 할당, newfd에 이미 있으면 엔트리 닫고 할당
    새로운 fd 반환
redirection 기능을 하고, 기존 fd에 엔트리는 유지됨
따라서, system file table의 count는 2가 되고, inode의 count는 1유지
  • int select(int n, fd_set readfds, fd_set writefds, fd_set exceptfds, struct timeval timeout)
    I/O 준비가 된 파일 디스크립터 번호 반환
int n는 세팅된 가장 큰 fd번호임을 알려주는 힌트이지만 의미 없다.
fd_set: 파일 디스크립터 집합, 각 집합의 인덱스(각 비트)를 매번 검사하며
1로 켜져있는 비트(기다릴 fd)들 중 하나라도 깨어나면 fd_set초기화 후, 깨어난 fd번호를 1로 다시 만들어서 찾음

하지만, fd전체를 매번 검사해야하기 때문에 낭비고, 커널이 항상 검사해야 하기 때문에 좋지 않다.
fd_set 세팅 매크로
FD_CLR(int fd, fd_set *set) : 해당 fd를 0으로 바꿈
FD_SET(int fd, fd_set *set) : 해당 fd를 1로 바꿈
FD_ISSET(int fd, fd_set * set) : 해당 fd가 세팅되있는지 확인
FD_ZERO(fd_set *set) : 모두 0으로 초기화
  • int pselect(int n, fd_set readfds, fd_set writefds, fd_set exceptfds, struct timeval timeout, const sigset_t *sigmask)
    기다리기 직전 signal 설정을 하고 기다림, 나머지는 select와 동일


<poll.h>

struct pollfd {
	int fd;
    short events;  //기다리는 이벤트
    short revents;  //받은 이벤트, 커널이 세팅해줌
}

이 정의되어 있고, 각 multiplex할 fd마다 struct하나씩 만들면 됨.

  • int poll(struct pollfd *fds, unsigned int nfds, int timeout)
    pollfd 타입 배열이 nfds있다고 알려주고, event올 때까지 기다림
  • int ppoll(struct pollfd fds, unsigned int nfds, int timeout, const sigset_t sigmask)
profile
Backend Engineer

0개의 댓글