Linux 单例程序
在 Linux 系统中,有时你希望某个程序在同一时间只能运行一个实例,避免多个进程同时执行带来的资源冲突或逻辑错误。本文将介绍实现程序单实例运行的常见方法,包括:
- 使用文件锁(
flock) - 使用进程 ID 文件(PID 文件)
- 使用
ps命令检测已有实例
通过这些方法,你可以确保程序在系统中只运行一个实例。
使用文件锁(C 语言)
文件锁是一种常用的进程间同步机制,可以用来防止多个实例同时运行。
文件锁示例(使用 flock)
#include <sys/file.h>
#include <errno.h>
int pid_file = open("/var/run/whatever.pid", O_CREAT | O_RDWR, 0666);
int rc = flock(pid_file, LOCK_EX | LOCK_NB);
if(rc) {
if(EWOULDBLOCK == errno)
; // another instance is running
}
else {
// this is the first instance
}
文件锁示例(使用 lockf )
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("/tmp/my_program.lock", O_CREAT | O_RDWR, 0666);
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
// 尝试获取文件锁
if (lockf(fd, F_TLOCK, 0) < 0) {
printf("Another instance is running.\n");
exit(EXIT_FAILURE);
}
// 程序主体逻辑
printf("Program is running...\n");
sleep(30); // 模拟程序运行
// 释放文件锁
close(fd);
return 0;
}
在上述代码中,程序尝试对 /tmp/my_program.lock 文件加锁,如果加锁失败,说明已有实例在运行,程序将退出。
flock 和 lockf 的区别
lockf 和 flock 都可以用来实现文件加锁,但它们在底层机制、行为特性、兼容性等方面存在明显区别。
- 所属 API 不同
flock()是 BSD 系统引入的,Linux 也支持;lockf()是对fcntl()的封装,是 POSIX 标准的一部分,更具可移植性。
- 加锁机制不同
flock加锁简单粗暴,整个文件都被锁定;lockf(底层调用fcntl)是文件级锁,但按进程生效(多个 fd 共享),适合数据库、日志等多进程并发写入部分区域的场景。
- 锁类型支持不同
lockf实际支持的是排他锁(写锁),并且是通过fcntl实现的。
- 子进程继承性不同
- 无论是
flock还是lockf,子进程都可以继承锁。但flock更依赖于文件描述符的存在(同描述符),如果 fd 被关闭,则锁立即释放;而lockf更依赖于进程的存在。
- 无论是
如果你需要在不同 Unix 系统或网络文件系统上使用,建议优先选择 lockf / fcntl。