NAME

flock - 열린 파일에 권고형 락 적용하고 제거하기

SYNOPSIS

#include <sys/file.h>

int flock(int fd, int operation);

DESCRIPTION

fd로 지정한 열린 파일 디스크립터에 권고형 락을 적용하거나 제거한다. opeartion 인자는 다음 중 하나다.

LOCK_SH
공유형 락을 둔다. 어떤 파일에 대해 어느 시점에 여러 프로세스가 공유형 락을 잡을 수 있다.
LOCK_EX
배타형 락을 둔다. 어떤 파일에 대해 어느 시점에 한 프로세스만 배타형 락을 잡을 수 있다.
LOCK_UN
이 프로세스가 잡은 기존 락을 제거한다.

호환되지 않는 락을 다른 프로세스에서 잡고 있으면 flock() 호출이 블록할 수 있다. 논블로킹 요청을 하려면 위 동작에 LOCK_NB를 (OR 해서) 포함시키면 된다.

한 파일에 공유형 락과 배타형 락이 동시에 있을 수 없다.

flock()으로 만든 락은 열린 파일 기술 항목(open(2) 참고)에 연계돼 있다. 따라서 (예를 들어 fork(2)dup(2)으로 만들어진) 복제 파일 디스크립터들이 같은 락을 가리키며, 그 파일 디스크립터들 어느 것으로도 락을 변경하거나 놓을 수 있다. 그리고 그 복제 파일 디스크립터들 중 하나에서 명시적으로 LOCK_UN 동작을 하거나 그 파일 디스크립터들이 모두 닫힐 때 락이 해제된다.

한 프로세스에서 open(2)을 (또는 비슷한 함수를) 이용해 같은 파일에 대한 파일 디스크립터를 여러 개 얻은 경우에는 flock()에서 그 파일 디스크립터들을 별개로 다룬다. 호출 프로세스에서 그 중 하나로 이미 잡은 락을 다른 파일 디스크립터로 잠그려고 시도하면 거부될 수 있다.

프로세스가 한 파일에 대해 (공유 또는 배타) 한 종류의 락만 잡을 수 있다. 이미 잠근 파일에 flock() 호출을 하면 기존 락이 새로운 락 모드로 바뀌게 된다.

flock()으로 생성된 락이 execve(2)를 거치면서 유지된다.

파일을 연 모드와 상관없이 공유형 락이나 배타형 락을 둘 수 있다.

RETURN VALUE

성공 시 0을 반환한다. 오류 시 -1을 반환하며 오류를 나타내도록 errno를 설정한다.

ERRORS

EBADF
fd가 열린 파일 디스크립터가 아니다.
EINTR
락 획득을 기다리는 동안 핸들러에 잡힌 시그널 전달에 의해 호출이 중단됐다. signal(7) 참고.
EINVAL
operation이 유효하지 않다.
ENOLCK
커널에서 락 레코드를 할당할 메모리가 부족하다.
EWOULDBLOCK
파일이 잠겨 있으며 LOCK_NB 플래그를 사용했다.

CONFORMING TO

4.4BSD (4.2BSD에서 flock() 호출이 처음 등장). 대부분의 유닉스 시스템에 fcntl(2)을 이용해 구현된 듯한 flock() 버전이 있다.

NOTES

커널 2.0부터 GNU C 라이브러리에서 fcntl(2) 호출로 에뮬레이션하지 않고 자체 시스템 호출로 flock()을 구현한다. 이 구현 방식에선 flock()fcntl(2)로 두는 락 사이에 상호작용이 없으며 flock()에서 교착을 탐지하지 않는다. (다만 최근 BSD 계열들 같은 일부 시스템에선 flock()fcntl(2) 락이 상호작용한다.)

flock()에서 두는 락은 권고형일 뿐이다. 파일에 대한 적절한 권한이 있으면 프로세스에서 얼마든 flock() 사용을 무시하고 파일에 I/O를 수행할 수 있다.

flock()의 락과 fcntl(2)의 락은 프로세스 포크와 dup(2) 측면에서 동작 방식이 다르다. fcntl(2)flock()을 구현하고 있는 시스템에서는 flock()의 동작 방식이 이 매뉴얼 페이지의 설명과 달라진다.

락 변환(공유를 배타로, 또는 반대로)이 원자적이라고 보장되지 않는다. 즉, 먼저 기존 락을 제거하고서 새 락을 수립한다. 이 두 단계 사이에서 다른 프로세스의 락 요청이 수락될 수 있으며, 그러면 변환 동작이 블록하게 된다. LOCK_NB를 지정했으면 실패한다. (이는 원본 BSD의 동작 방식이며 다른 여러 구현체에서도 볼 수 있다.)

NFS 세부 사항

리눅스 커널 2.6.11까지에서 flock()은 NFS 상의 파일을 잠그지 않는다. (즉, 락의 유효 범위가 로컬 시스템으로 국한되었다.) 충분히 최신 버전의 리눅스를 쓰고 서버에서 지원하는 경우에는 NFS 상에서 동작하는 fcntl(2)의 바이트 범위 락킹을 대신 이용할 수 있었다.

리눅스 2.6.12부터는 NFS 클라이언트에서 전체 파일에 대한 fcntl(2) 바이트 범위 락인 것처럼 에뮬레이션하는 방식으로 flock() 락을 지원한다. 따라서 NFS 상에서 fcntl(2)flock()이 상호작용한다. 그리고 배타적 락을 두려면 파일을 쓰기용으로 열어야 한다.

리눅스 2.6.37부터는 flock()락을 (그리고 fcntl(2) 바이트 범위 락도) 로컬로 다룰 수 있는 호환 모드를 지원한다. nfs(5)local_lock 옵션 설명 참고.

SEE ALSO

flock(1), close(2), dup(2), execve(2), fcntl(2), fork(2), open(2), lockf(3), lslocks(8)

리눅스 커널 소스 트리의 Documentation/filesystems/locks.txt (옛날 커널에선 Documentation/locks.txt)


2021-03-22