读书笔记:第9章 记录上锁 (6)

《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

你可能感兴趣的:(读书笔记,《UNIX网络编程》)