Есть ли блокировка файлов в Rust?

Я изучаю Rust примерно 3 часа и не могу найти ничего похожего на блокировку файлов (вы знаете, как некоторые программы используют в Linux, чтобы предотвратить запуск нескольких экземпляров).

например. в Python я бы использовал этот модуль: https://github.com/openstack/pylockfile

Я не замечаю подобную функциональность в Rust, или я должен просто реализовать ее с нуля?

Не ленив, просто пытаюсь изобрести как можно меньше колес.

Ответ 1

Для современного Rust (1.8+) вы должны использовать fs2 crate. Это кросс-платформенная библиотека, которая предоставляет некоторые функции файловой системы, не найденные в стандартной библиотеке, включая блокировку файлов.

fs2 функции блокировки файлов внутренне используют flock(2) в UNIX и LockFileEx в Windows.

Пример:

//! This program tries to lock a file, sleeps for N seconds, and then unlocks the file.

// cargo-deps: fs2
extern crate fs2;

use fs2::FileExt;
use std::io::Result;
use std::env::args;
use std::fs::File;
use std::time::Duration;
use std::thread::sleep;

fn main() {
    run().unwrap();
}

fn run() -> Result<()> {
    let sleep_seconds = args().nth(1).and_then(|arg| arg.parse().ok()).unwrap_or(0);
    let sleep_duration = Duration::from_secs(sleep_seconds);

    let file = File::open("file.lock")?;

    println!("{}: Preparing to lock file.", sleep_seconds);
    file.lock_exclusive()?; // block until this process can lock the file
    println!("{}: Obtained lock.", sleep_seconds);

    sleep(sleep_duration);

    println!("{}: Sleep completed", sleep_seconds);
    file.unlock()?;
    println!("{}: Released lock, returning", sleep_seconds);

    Ok(())
}

Мы видим, что два процесса секвенированы в ожидании блокировки файла.

$ ./a 4 & ./a 1
[1] 14894
4: Preparing to lock file.
4: Obtained lock.
1: Preparing to lock file.
4: Sleep completed
4: Released lock, returning
1: Obtained lock.
1: Sleep completed
1: Released lock, returning
[1]+  Done                    ./a 4

Ответ 2

В Linux вы можете использовать nix crate, который wraps unix file lock.

Вот пример:

extern crate nix;

use std::fs::File;
use std::os::unix::io::AsRawFd;
use nix::fcntl::{flock, FlockArg};

fn main() {
    let file = File::open("Cargo.toml").unwrap();
    let fd = file.as_raw_fd();
    flock(fd, FlockArg::LockExclusive).unwrap();

    for rem in (1..20).rev() {
        println!("Remain: {} sec.", rem);
        std::thread::sleep(std::time::Duration::from_secs(1));
    }

    drop(file);
    println!("File unlocked!");
}

Если вы попытаетесь запустить два экземпляра, второй начнет обратный отсчет только после разблокированного файла первого экземпляра. Но другие программы могут игнорировать эту блокировку:

flock (2): функция фиксирует только контрольные блокировки; с учетом соответствующих разрешений на файл, процесс может игнорировать использование flock() и выполнять ввод/вывод в файле.