您的位置:首页 > 运维架构 > Linux

linux下的单实例进程 - 一个进程不能重复启动

2016-05-04 11:42 1251 查看
最近项目中的一个计数程序,因为会计数,所以只能有一个进程在运行,否则计数速度会加快,而刚好又是一个守护进程。Steven的《unix环境高级编程》的守护进程中就有讲,单实例进程。

这种监控有很多,如果放在两年前,我可能会用shell脚本,但这真的是一个又懒又笨又漏洞百出的方法了。写下我知道的都有什么方法:

1 shell使用ps命令来判断

2 信号量/共享内存

3 创建文件写入0或1作为启动/关闭标志,异常退出

4 创建文件,加锁(建议性锁),daemon进程写pid文件,/var/run/xx.pid

首先,方法1, 进程名字改变无法监控,又外加了脚本,实在多余

方法2, 这个可以尝试,守护进程用信号量不知道会不会有什么问题,有时间的话可以研究下。

方法3,呃,也是个笨方法了,程序异常退出等无法及时改文件的话就有问题。

方法4,我采用的方法了,感觉很可靠,程序退出释放锁,是不是很靠谱呢。

先解释下这个函数的机制,在”/var/run/”目录下建立一个文件,一般是以进程名字命名。里面只写入进程号。注意,这个目录是默认守护进程会写的目录,所以建议大家遵循这个规则。(关于守护进程默认遵循的规则,比如自动重启,作为服务启动关闭等,参考该书即可)

该文件加建议性写锁,进程在运行期间一直持有该锁,不释放,而是在进程退出后自动释放。所以获取该锁失败就说明进程已经在运行。直接退出。

函数中写日志接口是项目中的日志模块,可以直接用linux系统中的syslog日志服务进行监控。

函数中加锁的函数采用fcntl函数,可以参考该书中对fcntl的封装,用起来非常方便。文章最后附上该封装函数。

如果是守护进程,该函数需要在daemon后调用,因为daemon函数会对文件描述符做操作。

如果不是守护进程,直接调用就OK了

#define LOCKFILE "/var/run/xxxx.pid"

static int already_running(void)

{

int fd;

char buf[32];

fd = open(LOCKFILE, O_RDWR|O_CREAT, 0644);

if (fd < 0) {

write_log(IRILOG_ERR, "Iridium license daemon start fail!");

exit(1);

}

/* 加建议性写锁 */

if (write_lock(fd, 0, SEEK_SET, 0) < 0) {

close(fd);

exit(1);

}

ftruncate(fd, 0); /* 文件清零,因为只写一次pid号
*/

snprintf(buf, 32, "%ld", (long)getpid());

write(fd, buf, strlen(buf)+1);

return(0);

}

=============== fcntl函数封装 =============================

头文件:

#ifndef WRAPFCNTL_H

#define WRAPFCNTL_H

#include <stdio.h>

#include <string.h>

#include <sys/types.h> /* about files */

#include <sys/stat.h>

#include <sys/file.h>

#include <fcntl.h>

#include <unistd.h>

#include <pthread.h>

/* fcntl函数的包装,带w表示阻塞调用*/

#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 writew_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))

int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len);

#endif

.c文件

#include "wrapfcntl.h"

int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)

{

struct flock lock;

lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */

lock.l_start = offset; /* byte offset, relative to l_whence */

lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */

lock.l_len = len; /* #bytes (0 means to EOF) */

return (fcntl(fd, cmd, &lock));

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: