《UNIX网络编程:卷2》P171:图9-11
记录上锁的一个常见用途是确保某个程序(如守护程序)在任何时刻只有一个副本在运行。
--------------------------------------------
/* * onedaemon.c * P171 图9-11 确保某个程序只有一个副本在运行 */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <errno.h> #define read_lock(fd, offset, whence, len) \ lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len) #define readw_lock(fd, offset, whence, len) \ lock_reg(fd, F_SETLKW, F_RDLCK, offset, whence, len) #define write_lock(fd, offset, whence, len) \ lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len) #define wrtiew_lock(fd, offset, whence, len) \ lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, len) #define un_lock(fd, offset, whence, len) \ lock_reg(fd, F_SETLK, F_UNLCK, offset, whence, len) #define is_read_lockable(fd, offset, whence, len) \ !lock_test(fd, F_RDLCK, offset, whence, len) #define is_write_lockable(fd, offset, whence, len) \ !lock_test(fd, F_WRLCK, offset, whence, len) #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) #define MAXLINE 1024 #define PATH_PIDFILE "pidfile" int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len); int lock_test(int fd, int type, off_t offset, int whence, off_t len); int main(int argc, char *argv[]) { int pidfd; char line[MAXLINE]; /* * 打开一个文件并为其上锁 */ if ((pidfd = open(PATH_PIDFILE, O_RDWR | O_CREAT, FILE_MODE)) < 0) { fprintf(stderr, "open error: %s\n", strerror(errno)); exit(1); } if (write_lock(pidfd, 0, SEEK_SET, 0) < 0) { if (errno == EACCES || errno == EAGAIN) { fprintf(stderr, "unable to lock %s, is %s already running ?\n", PATH_PIDFILE, argv[0]); exit(1); } else { fprintf(stderr, "unable to lock %s\n", PATH_PIDFILE); } } snprintf(line, sizeof(line), "%d\n", getpid()); /* * 把文件截短,然后将本进程PID写入文件 */ ftruncate(pidfd, 0); if (write(pidfd, line, strlen(line)) < 0) { fprintf(stderr, "write error: %s\n", strerror(errno)); exit(1); } pause(); exit(0); } int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len) { struct flock lock; lock.l_type = type; lock.l_start = offset; lock.l_whence = whence; lock.l_len = len; return(fcntl(fd, cmd, &lock)); } int lock_test(int fd, int type, off_t offset, int whence, off_t len) { struct flock lock; lock.l_type = type; lock.l_start = offset; lock.l_whence = whence; lock.l_len = len; if (fcntl(fd, F_GETLK, &lock) == -1) return(-1); if (lock.l_type == F_UNLCK) return(0); return(lock.l_pid); }
--------------------------------------------
运行程序:
$ ./onedaemon & 启动第一个副本 [1] 2847 $ cat pidfile 检查写入文件中的PID 2847 $ ./onedaemon & 尝试启动第二个副本 [2] 2851 $ unable to lock pidfile, is ./onedaemon already running ? [2]+ 退出 1 ./onedaemon