파일 닫기
close() 시스템 콜
1 2 3 | #include <unistd.h> int close(int fd); |
인자로 받은 파일 디스크립터 fd와 연관된 파일 매핑을 해제하며, 프로세스에서 파일을 떼어내는 작업을 한다. 이 과정을 거치면 파일 디스크립터는 더는 유효하지 않으며, 커널이 다음 open()이나 creat() 호출에서 다시 사용할 수 있게 된다. close()도 지금까지 다룬 대부분의 시스템 콜과 마찬가지로 성공하면 0, 실패하면 -1을 반환하고 errno를 적절한 값으로 설정한다. 아래는 파일을 일단 연 후, close()로 다시 닫는 간단한 예제이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main() { fd = open("TEXT", O_RDWR | O_CREAT | O_SYNC, 0666) if(fd == -1) perror("Failed to open file.\n"); else printf("Successfully opened file!\n"); if(clos(fd) == -1) perror("Failed to close file.\n"); else printf("Successfully closed file!\n"); return 0; } | cs |
사실 close() 시스템 콜 자체가 단순한 구조라서 크게 다룰 것은 없다. 파일을 닫더라도 파일을 디스크에 강제로 쓰는 것은 아니라는 점을 기억하자. 파일을 닫기 전에 디스크에 확실히 기록을 하기 위해서는 애플리케이션에서 동기식 입출력 방법 중 하나를 사용해야 한다.
close()로 파일을 닫을 경우 몇 가지 부작용이 발생할 수 있다. 마지막으로 열린 파일 디스크립터가 닫히면 커널 내부에서 그 파일을 표현하는 자료구조를 해제한다. 그 자료구조가 해제되면 커널은 메모리에서 해당 파일과 관련된 inode 복사본을 제거한다. inode를 참조하는 객체가 없으면 커널은 그 inode 복사본을 메모리에서 제거할 수 있다. 만약 파일이 디스크에서 연결이 끊길 때 열려 있는 상태였다면, 파일이 닫히고 inode 복사본이 삭제될 때까지 물리적으로는 메모리에서 찌꺼기처럼 남아 있을 가능성이 있다. 1
에러 값
close() 쓰고~ 대충 닫고~ 끝~!!!
아주 큰 실수다! close()의 반환값을 검사하지 않는 경우 심각한 에러를 놓칠 수 있다. 지연된 연산에 의한 에러는 한참 후에도 나타나지 않기 때문에 놓치기 십상인데, close() 반환값을 통해 이를 알아낼 수 있기 때문이다.
close() 호출이 실패했을 때 확인할 수 있는 유용한 errno 값은 EBADF, EIO가 있다.
에러 코드 |
설명 |
EBADF |
파일 디스크립터가 유효하지 않음 |
EIO |
저수준의 입출력 에러 |
EIO는 특히 중요한 값이다! 저수준의 입출력 에러를 나타낸다는 저 설명 자체는 실제 파일 닫기와는 무관해 보일 수도 있는데, close() 호출 시 발생한 에러와 관계 없이 파일 디스크립터가 유효하다면 파일은 항상 닫히며 관련된 자료구조 역시 일반적으로 메모리에서 해제된다.
비록 POSIX에서는 허용하고 있긴 하지만, 대부분의 경우 리눅스 커널 개발자들에 의해 close() 시스템 콜은 EINTR을 반환하지 않는다.
- 파일을 닫더라도 inode 복사본이 메모리에 남아 있는 이유는 성능상의 이유로 inode를 캐시하기 때문이다. 하지만 반드시 그럴 필요는 없다. [본문으로]
'System > System Programming' 카테고리의 다른 글
8. 지정한 위치 읽고 쓰기 - pread(), pwrite() (0) | 2019.04.29 |
---|---|
7. 파일 탐색하기 - lseek() (0) | 2019.04.25 |
5. 직접 입출력 (0) | 2019.04.24 |
4. 동기식 입출력 - fsync(), fdatasync() (2) | 2019.04.22 |
3. 파일 쓰기 - write() (0) | 2019.04.16 |