POSIX fcntl vs BSD flock: choosing Unix advisory file locks
Choose between POSIX fcntl record locks and BSD flock for Unix file coordination. Compare semantics, fork behavior, and NFS caveats before implementation.
03 Jul 2026, 21:42 UTC

The problem: coordinating shared files across processes
When two or more Unix processes write to the same file, uncoordinated access can corrupt data or leave it in an inconsistent state. Advisory locks are the standard lightweight solution: they work only when all participating processes agree to respect them. Unix provides two distinct APIs: POSIX fcntl record locks and BSD-derived flock advisory locks.
Useful takeaway: choose fcntl when you need POSIX portability, byte-range locking, or per-process ownership. Choose flock when you need simple whole-file exclusion and open-file-description semantics. Never mix the two on the same file.
Decision and constraints
Before selecting an API, answer these constraints:
- Granularity: Do processes need to lock different byte ranges of the same file, or is whole-file exclusion sufficient?
- Portability: Is the code required to run on strict POSIX systems, or is BSD-derived behavior acceptable?
- Process model: Will the program fork, duplicate file descriptors, or run as a long-lived daemon that opens the same file multiple times?
- Filesystem: Is the target file on a local disk or NFS?
Supported options compared
| Factor | fcntl record locks (fcntl(2)) | flock advisory locks (flock(2)) |
|---|---|---|
| Standard | POSIX.1-2008 | BSD-derived; not part of POSIX |
| Granularity | Byte ranges within a file | Entire file only |
| Lock owner | Process and inode | Open file description |
| Fork behavior | Child does not inherit parent's locks | Not inherited across fork |
| Duplicated descriptors | All descriptors in the process share and release locks together | Duplicated descriptors share the same open-file-description lock |
| Release trigger | Closing any descriptor for the file releases all locks for that process | Closing the last descriptor for the open file description releases the lock |
| Own I/O | A locked range does not block the same process's own I/O on that descriptor | Behavior through shared descriptors depends on the open file description |
| NFS | Historically relies on lockd/statd; version-dependent caveats | Depends on NFS version and client implementation |
Trade-offs that matter in production
fcntl: precision with surprising close semantics
fcntl locks are tied to the process and inode. This means a process can lock byte range A while another process locks byte range B in the same file. The risk is the close rule: if a daemon opens a data file, takes a lock, then opens the same file again for logging and closes that second descriptor, the first lock is released. Long-running processes that open the same file multiple times must track this carefully.
flock: simplicity with whole-file scope
flock locks the entire file. It is easier to reason about when only one writer should touch a file at a time, but it cannot protect independent regions of a large file. Because it is not POSIX, it may be absent or behave differently on some proprietary Unix systems. It is also unsuitable when two processes need to modify different parts of the same file concurrently.
Never mix the two
Do not call fcntl and flock on the same file. Their interaction is unspecified and varies by operating system and filesystem. Pick one mechanism per file and document it.
Concrete implementation: flock in a shell script
The flock(1) command-line wrapper (common on Linux and BSD-derived systems) makes whole-file locking practical in shell automation. This example prevents overlapping nightly backup runs.
#!/bin/sh
# Where to run: terminal, cron, or systemd timer on a Unix-like system
# Permissions: the user needs write access to the lock file path
LOCKFILE=/var/lock/nightly-backup.lock
# Open file descriptor 9 for writing, creating the lock file if needed
exec 9>"$LOCKFILE"
# -n: fail immediately if the lock is held by another process
if ! flock -n 9; then
echo "Another backup is already running" >&2
exit 1
fi
# Critical section: only one instance proceeds here
echo "Backup started"
# ... backup commands ...
echo "Backup finished"
# Closing descriptor 9 releases the lock
exec 9>&-
Expected check: run two instances simultaneously. The second should print the error message and exit with a non-zero status. Risk: advisory locks only cooperate; a process that ignores flock can still write to the file.
Concrete implementation: fcntl record lock in C
For byte-range control, use fcntl(2). This illustrative example locks an entire file by setting l_len to zero, which means "lock through end of file."
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(void) {
int fd = open("datafile", O_RDWR | O_CREAT, 0644);
if (fd < 0) {
perror("open");
return 1;
}
struct flock lock = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 0, /* 0 locks to EOF */
};
/* F_SETLKW blocks until the lock is available or a signal interrupts */
if (fcntl(fd, F_SETLKW, &lock) == -1) {
perror("fcntl");
close(fd);
return 1;
}
/* Critical section */
printf("Lock acquired\n");
close(fd); /* Releases all fcntl locks on this file for this process */
return 0;
}
Where to run: compile with cc -o lockdemo lockdemo.c and execute as a normal user with read/write access to datafile. Expected check: start one instance, then start a second; the second should block until the first closes the file. Risk: closing any other descriptor for datafile in the same process releases this lock, even if the critical section is not finished.
Validation checklist
- Inspect
man 2 fcntlandman 2 flockon the target system forEAGAIN,EINTR,EDEADLK, and filesystem-specific notes. - Run two lock-contending processes on the target filesystem and confirm mutual exclusion.
- If the file resides on NFS, test lock behavior in staging before production deployment; both mechanisms have version-dependent caveats.
Limitations
- Advisory locks do not prevent access from non-cooperating processes.
fcntllocks can vanish unexpectedly when any descriptor for the file is closed.flockis not portable to all POSIX-only systems.- NFS locking reliability depends on lockd/statd, NFS version, and client implementation.
How to verify the result
After implementing, run the lock holder and a lock waiter in separate terminals. Confirm the waiter blocks until the holder exits or closes the file. Check the return codes of flock -n or fcntl to distinguish "lock acquired" from "lock unavailable." On NFS, repeat the test after a client or server restart to confirm lock recovery behavior.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.