Mastering File Locks in Linux: flock vs lockf vs fcntl Explained
This article compares Linux file locking mechanisms—flock, lockf, and fcntl—detailing their prototypes, lock types, behavior with forks, dup, exec, and NFS, and provides practical code examples illustrating differences in lock scope, recursion, and interaction between advisory and POSIX locks.
1. flock
Function prototype
int flock(int fd, int operation); // Apply or remove an advisory lock on the open file specified by fd. fd is the file descriptor returned by open. operation options include:
LOCK_SH: shared lock
LOCK_EX: exclusive lock
LOCK_UN: unlock
LOCK_NB: non‑blocking (used with the above)
flock locks the whole file and only creates advisory locks. Unlike fcntl/lockf, it cannot lock a file region.
Key differences related to fork and dup:
flock’s lock is associated with the file table entry (struct file), not the fd. Duplicating the fd via fork or dup shares the same lock; closing one fd does not release the lock until all duplicates are closed.
Program 1
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main(int argc, char **argv) {
int ret;
int fd1 = open("./tmp.txt", O_RDWR);
int fd2 = dup(fd1);
printf("fd1: %d, fd2: %d
", fd1, fd2);
ret = flock(fd1, LOCK_EX);
printf("get lock1, ret: %d
", ret);
ret = flock(fd2, LOCK_EX);
printf("get lock2, ret: %d
", ret);
return 0;
}Running this shows that locking fd1 does not prevent fd2 (a duplicate) from acquiring the lock.
Program 2
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main(int argc, char **argv) {
int ret;
int pid;
int fd = open("./tmp.txt", O_RDWR);
if ((pid = fork()) == 0) {
ret = flock(fd, LOCK_EX);
printf("child get lock, fd: %d, ret: %d
", fd, ret);
sleep(10);
printf("child exit
");
exit(0);
}
ret = flock(fd, LOCK_EX);
printf("parent get lock, fd: %d, ret: %d
", fd, ret);
printf("parent exit
");
return 0;
}The child’s lock does not affect the parent’s ability to lock the same fd, and vice‑versa.
Program 3
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main(int argc, char **argv) {
int ret;
int fd1 = open("./tmp.txt", O_RDWR);
int fd2 = open("./tmp.txt", O_RDWR);
printf("fd1: %d, fd2: %d
", fd1, fd2);
ret = flock(fd1, LOCK_EX);
printf("get lock1, ret: %d
", ret);
ret = flock(fd2, LOCK_EX);
printf("get lock2, ret: %d
", ret);
return 0;
}When the same file is opened twice, the second fd cannot acquire the lock while the first holds it.
Additional observations:
flock cannot be used on NFS; use fcntl instead.
flock locks are recursive: dup or forked descriptors can lock without deadlock.
Locks are released when the process terminates.
2. lockf and fcntl
Function prototype
int lockf(int fd, int cmd, off_t len);
cmd values:
F_LOCK: block until the lock is acquired.
F_TLOCK: non‑blocking; returns error if the lock cannot be obtained.
F_ULOCK: unlock.
F_TEST: test whether the file is locked.
lockf only supports exclusive locks; it cannot create shared locks.
fcntl
int fcntl(int fd, int cmd, ... /* arg */ );
struct flock {
short l_type; /* F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* start offset */
off_t l_len; /* length */
pid_t l_pid; /* PID of locking process (F_GETLK only) */
};fcntl supports both shared and exclusive locks and can lock whole files or specific regions.
Key properties of fcntl/lockf:
Locks are recursive; a new lock on the same region replaces the old one.
Read locks require the file to be opened read‑only; write locks require write access.
A process cannot use F_GETLK to test its own lock; the command reports only locks held by other processes.
All locks are released when the process exits, similar to flock.
Closing a descriptor releases any locks set through that descriptor, unlike flock.
Locks set by a parent are not inherited by a child created with fork, unlike flock.
Locks survive exec unless the close‑on‑exec flag is set.
Mandatory locks can be enabled by setting the set‑gid bit on the file and clearing the group‑execute bit, and mounting the filesystem with the appropriate option.
3. Interaction between flock and lockf/fcntl
Locks created by flock and those created by lockf/fcntl are independent and do not interfere with each other. The following test demonstrates this:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
int main(int argc, char **argv) {
int fd, ret;
fd = open("./tmp.txt", O_RDWR);
ret = flock(fd, LOCK_EX);
printf("flock return ret : %d
", ret);
ret = lockf(fd, F_LOCK, 0);
printf("lockf return ret: %d
", ret);
sleep(100);
return 0;
}Both calls succeed (return 0), showing that a flock lock does not prevent a lockf lock. The locks can be observed via /proc/locks, which lists a POSIX advisory write lock (from lockf) and an FLOCK advisory write lock (from flock) for the same process.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
