rust 91 lines · 3 tabs

RAII File Lock Guard in Rust With Drop-Based Release

Shared by codesnips Jul 2026
3 tabs
use std::os::raw::c_int;

pub const LOCK_EX: c_int = 2;
pub const LOCK_NB: c_int = 4;
pub const LOCK_UN: c_int = 8;

extern "C" {
    pub fn flock(fd: c_int, operation: c_int) -> c_int;
}
3 files · rust Explain with highlit

This snippet shows the RAII (Resource Acquisition Is Initialization) pattern applied to an advisory file lock, where acquiring the lock produces a guard whose Drop implementation releases it automatically when the guard leaves scope. The core idea is that ownership tracks the lock's lifetime: as long as the guard value lives, the lock is held; the moment it is dropped — normally, via early return, or during an unwinding panic — the destructor runs and the lock is freed. This eliminates the classic bug of forgetting to unlock, or leaking a lock on an error path.

In flock.rs, the FFI declarations pull in flock from libc along with the LOCK_EX, LOCK_UN, and LOCK_NB constants. Wrapping raw C calls behind a tiny extern block keeps the unsafe surface small and explicit. The flock syscall places an advisory lock on an open file descriptor, so the lock is tied to the descriptor rather than the path, which matters for the guard design.

In lock.rs, FileLock owns a File and exposes acquire, which blocks, and try_acquire, which uses LOCK_NB to fail fast when the lock is contended. Both return a FileLockGuard that borrows the lock, so the borrow checker prevents a second acquisition while the guard exists. The guard holds only &'a File and a RawFd, keeping it cheap to move. Its Drop impl calls flock(fd, LOCK_UN) exactly once; the return value is deliberately ignored because a destructor cannot propagate errors and must not panic. Using as_raw_fd rather than closing the File ensures the descriptor stays valid for the parent FileLock.

A subtle point is unlock-on-panic: because Rust runs destructors during stack unwinding, the lock is released even if the guarded critical section panics, which a manual unlock() call would miss. The trade-off is that advisory locks only coordinate cooperating processes and are not enforced by the kernel against arbitrary writers.

In main.rs, a nested scope demonstrates the lifetime: the guard is created inside a block, the critical section runs, and the lock is provably released at the closing brace before the next try_acquire runs. This is exactly when a developer reaches for RAII guards — any resource with a clear paired acquire/release that must survive early returns and panics.


Related snips

Share this code

Here's the card — post it anywhere.

RAII File Lock Guard in Rust With Drop-Based Release — share card
Link copied