Skip to content

close(2)

Seonghun Lim edited this page May 14, 2019 · 4 revisions

NAME

close - 파일 디스크립터 닫기

SYNOPSIS

#include <unistd.h>

int close(int fd);

DESCRIPTION

close()는 파일 디스크립터를 닫아서 더 이상 어떤 파일도 가리키지 않으며 재사용할 수 있게 만든다. 연계된 파일에 레코드 락(fcntl(2) 참고)이 잡힌 게 있고 그 프로세스 소유이면 (그 락을 얻는 데 어떤 파일 디스크립터를 썼는지 상관없이) 그 락을 제거한다.

fd가 하위 열린 파일 기술 항목(open(2) 참고)을 가리키는 마지막 파일 디스크립터이면 그 열린 파일 기술 항목 관련 자원들이 해제된다. 또 그 파일 디스크립터가 unlink(2)로 제거된 파일에 대한 마지막 참조이면 파일이 삭제된다.

RETURN VALUE

성공 시 close()가 0을 반환한다. 오류 시 -1을 반환하며 errno를 적절히 설정한다.

ERRORS

EBADF
fd가 유효한 열린 파일 디스크립터가 아니다.
EINTR
close() 호출이 시그널에 의해 중단되었다. signal(7) 참고.
EIO
I/O 오류가 발생했다.
ENOSPC, EDQUOT
NFS에서는 이 오류들이 가용 저장 공간을 초과하는 첫 번째 쓰기에서 정상적으로 보고되지 않고 이후의 write(2), fsync(2), close()에서 보고된다.

오류 시 close()를 재시도하지 말아야 하는 이유에 대한 NOTES의 설명을 보라.

CONFORMING TO

POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.

NOTES

닫기에 성공했다는 게 데이터가 성공적으로 디스크에 저장됐다는 걸 보장하지는 않는다. 커널에서 버퍼 캐시를 써서 쓰기를 연기하기 때문이다. 일반적으로 파일 시스템에서는 파일이 닫힐 때 버퍼를 플러시 하지 않는다. 기반 디스크에 데이터가 물리적으로 저장되게 해야 한다면 fsync(2)를 써라. (그 다음부터는 디스크 하드웨어에게 달렸다.)

'exec에서 닫기' 파일 디스크립터 플래그를 쓰면 execve(2) 성공 시 파일 디스크립터가 자동으로 닫히도록 할 수 있다. 자세한 내용은 fcntl(2) 참고.

그 파일 디스크립터를 같은 프로세스의 다른 스레드에서 시스템 호출로 사용 중일 수도 있을 동안에 닫는 건 그리 현명한 일이 아니다. 파일 디스크립터가 재사용될 수도 있기 때문에 의도치 않은 부작용을 유발하는 잡아내기 힘든 경쟁 조건이 있을 수 있다.

close()의 오류 반환 다루기

세심한 프로그래머라면 close()의 반환 값을 확인할 것이다. 앞선 write(2) 동작에서의 오류가 열린 파일 기술 항목을 해제하는 마지막 close()에서만 보고되는 일도 충분히 가능하기 때문이다. 파일을 닫을 때 반환 값 검사를 하지 않는 게 조용한 데이터 유실로 이어질 수도 있다. 특히 NFS와 디스크 쿼터에서 이런 경우를 볼 수 있다.

단, 실패 반환 값은 진단 용도(즉 미처리 I/O가 아직 있거나 실패한 I/O가 있었을 수도 있음을 응용에게 알려주기)나 보완 용도(가령 파일에 한 번 더 쓰거나 백업 만들기)로만 쓰는 게 좋다.

실패 반환 후에 close()를 재시도하는 건 바람직하지 못한 처리 방식이다. 다른 스레드에서 재사용된 파일 디스크립터를 닫히게 할 수도 있기 때문이다. 리눅스 커널에서는 닫기 동작 초반에서 항상 파일 디스크립터를 해제하여 재사용 될 수 있게 만들기 때문에 그런 일이 생길 수 있다. 파일 시스템이나 장치로 데이터를 플러시 하는 것처럼 오류를 반환할 수 있는 단계들은 닫기 동작 후반에서 이뤄진다.

여러 다른 구현들에서도 마찬가지로 이후 close() 반환에서 오류를 보고하더라도 (파일 디스크립터가 유효하지 않다는 뜻인 EBADF 경우를 제외하고) 파일 디스크립터를 항상 닫는다. POSIX.1에서는 현재 이 점에 대해 아무 언급이 없지만 표준 다음 주 릴리스 때 이 동작을 강제화할 계획이 있다.

I/O 오류에 대해 알고 싶은 세심한 프로그래머라면 close() 전에 fsync(2) 호출을 할 수 있다.

EINTR 오류는 다소 특별한 경우다. EINTR 오류와 관련해 POSIX-1.2013에서는 다음과 같이 말한다.

잡게 돼 있는 시그널에 의해 close()가 중단되는 경우 errnoEINTR로 설정해서 -1을 반환해야 하며 fildes의 상태는 명세되어 있지 않다.

이는 리눅스와 기타 여러 구현에서 이뤄지는, close()에서 보고하는 다른 오류들과 마찬가지로 파일 디스크립터가 닫힌다고 보장되는 동작 방식을 허용한다. 하지만 이는 다른 가능성 또한 허용한다. 즉 구현에서 EINTR 오류를 반환하면서 파일 디스크립터를 계속 열어 둘 수도 있다. (문서에 따르면 HP-UX의 close()에서 이렇게 한다.) 그러면 호출자는 파일 디스크립터 누출을 막기 위해 한 번 더 close()를 써서 파일 디스크립터를 닫아야 한다. 이러한 구현 동작 방식의 차이는 이식 가능한 응용에 어려운 장애물이 된다. 많은 구현에서는 EINTR 오류 후에 close()를 다시 호출해선 안 되지만 적어도 한 구현에서는 close()를 다시 호출해야 하는 것이다. POSIX.1 표준 다음 주 릴리스에서 이 난제를 다루려는 계획이 있다.

SEE ALSO

fcntl(2), fsync(2), open(2), shutdown(2), unlink(2), fclose(3)


2017-09-15

Clone this wiki locally