首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Pidfile单进程实例机制

Pidfile单进程实例机制
EN

Code Review用户
提问于 2019-05-23 12:27:06
回答 1查看 122关注 0票数 3

我正在用Rust编写一个系统守护进程,用户可以手动启动它。一次只应该运行一个守护进程实例,因此我创建了一个pidfile锁定机制来防止多个实例。这是我第一次做任何类型的unix风格的文件锁定,我希望能有另一双眼睛来检查我可能错过的任何东西。

风格指针也将是伟大的,因为我是新的锈。

代码语言:javascript
复制
use nix::fcntl::{flock, FlockArg};
use nix::sys::signal::kill;
use nix::unistd::Pid;
use std::fs::File;
use std::fs::OpenOptions;
use std::io;
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom, Write};
use std::os::unix::io::AsRawFd;
use std::path;
use std::process;

fn write_pid(mut file: &File) -> Result<(), io::Error> {
    let id = process::id().to_string() + "\n";
    file.write_all(id.as_bytes())?;
    Ok(())
}

fn lock_pidfile(file: &File, pidfile: &path::Path) -> Result<(), io::Error> {
    flock(file.as_raw_fd(), FlockArg::LockExclusiveNonblock).map_err(|_| {
        Error::new(
            ErrorKind::Other,
            format!("Failed to lock pidfile: {}", pidfile.display()),
        )
    })
}

pub fn exclusive(pidfile: &path::Path) -> Result<bool, io::Error> {
    let pf = OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(pidfile);

    match pf {
        Ok(file) => {
            lock_pidfile(&file, pidfile)?;
            write_pid(&file)?;
            Ok(true)
        }
        Err(err) => {
            match err.kind() {
                ErrorKind::AlreadyExists => {
                    let mut file = OpenOptions::new().read(true).write(true).open(pidfile)?;
                    lock_pidfile(&file, pidfile)?;
                    let mut id_str = String::new();
                    file.read_to_string(&mut id_str)?;
                    let id: u32 = id_str.trim().parse().map_err(|_| {
                        Error::new(
                            ErrorKind::Other,
                            format!("Failed to parse pidfile: {}", pidfile.display()),
                        )
                    })?;
                    // Kill None just checks if process exists.
                    // Same as kill(pid, 0); in C
                    if kill(Pid::from_raw(id as i32), None).is_ok() {
                        Ok(false)
                    } else {
                        file.seek(SeekFrom::Start(0))?;
                        write_pid(&file)?;
                        Ok(true)
                    }
                }
                _ => Err(err),
            }
        }
    }
}
```
代码语言:javascript
复制
EN

回答 1

Code Review用户

回答已采纳

发布于 2019-05-24 05:30:36

我对文件锁定不太了解,但我可以在铁锈里指导你。

我建议您将write_pid更改为使用writeln!。我想你可以把它简化成这样。

代码语言:javascript
复制
fn write_pid(mut file: &File) -> Result<(), io::Error> {
    writeln!(file, "{}", process::id())
}

我还希望减少exclusive中的嵌套,可能如下所示:

代码语言:javascript
复制
pub fn exclusive(pidfile: &path::Path) -> Result<bool, io::Error> {
    let pf = OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(pidfile);

    match pf {
        Ok(file) => {
            lock_pidfile(&file, pidfile)?;
            write_pid(&file)?;
            return Ok(true);
        }
        Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {}
        Err(e) => return Err(e),
    }

    let mut file = OpenOptions::new().read(true).write(true).open(pidfile)?;
    lock_pidfile(&file, pidfile)?;
    let mut id_str = String::new();
    file.read_to_string(&mut id_str)?;
    let id: u32 = id_str.trim().parse().map_err(|_| {
        Error::new(
            ErrorKind::Other,
            format!("Failed to parse pidfile: {}", pidfile.display()),
        )
    })?;
    // Kill None just checks if process exists.
    // Same as kill(pid, 0); in C
    if kill(Pid::from_raw(id as i32), None).is_ok() {
        Ok(false)
    } else {
        file.seek(SeekFrom::Start(0))?;
        write_pid(&file)?;
        Ok(true)
    }
}
票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/220825

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档