Linux flock实现单进程启动

#include <sys/file.h>
#include <unistd.h>
#include <fcntl.h>
using namespace std;

bool single_proc_running(const char *process_name)
{
    char lock_file[128];
    snprintf(lock_file, sizeof(lock_file), "/var/tmp/%s.lock", process_name);

    int lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644);
    if (-1 == lock_fd) 
    {
        fprintf(stderr, "Fail to open lock file(%s). Error: %s\n",lock_file,strerror(errno));
        return false;
    }

    if (0 == flock(lock_fd, LOCK_EX | LOCK_NB)) {
        return true;
    }

    close(lock_fd);
    lock_fd = -1;
    return false;

}

extern int Start();

int main()
{
    if(!single_proc_running("server"))
    {
        cout << "single server process can be created." << endl;
        return 0;
    }

    //执行任务
    int i = Start();
    if (i != 0)
    {
        cout << "Server Running failed." << endl;
    }

    return 0;
}

flock是建议性锁,不具备强制性。一个进程使用flock将文件锁住,另一个进程可以直接操作正在被锁的文件,修改文件中的数据,原因在于flock只是用于检测文件是否被加锁,针对文件已经被加锁,另一个进程写入数据的情况,内核不会阻止这个进程的写入操作,也就是建议性锁的内核处理策略。

第二个参数:
LOCK_SH,共享锁,多个进程可以使用同一把锁,常被用作读共享锁;
LOCK_EX,排他锁,同时只允许一个进程使用,常被用作写锁;
LOCK_UN,释放锁;

进程使用flock尝试锁文件时,如果文件已经被其他进程锁住,进程会被阻塞直到锁被释放掉,或者在调用flock的时候,采用LOCK_NB(非阻塞)参数,在尝试锁住该文件的时候,发现已经被其他服务锁住,会返回错误,errno错误码为EWOULDBLOCK。

flock锁的释放可调用LOCK_UN参数来释放文件锁,也可以通过关闭fd的方式来释放文件锁,意味着flock会随着进程的关闭而被自动释放掉。当打开文件的所有描述符被关闭时或者进程结束时,锁会自动释放,也可以手动释放(flock与fcntl不同,fcntl关闭一个文件描述符则锁释放,例如dup)

强制性加锁可以参考fcntl中的F_SETLK属性(不等待),F_SETLKW(等待)
fcntl函数设置的第三个参数的结构体如下:

struct flock
{
... 
short l_type;/* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */ 
off_t l_start;   /* Starting offset for lock */ 
off_t l_len;     /* Number of bytes to lock */ 
pid_t l_pid; /* PID of process blocking our lock (F_GETLK only) */ 
}

以下为简易流程:

int checkproc(char* pfile)
{
    if (pfile == NULL)
    {  
        return -1;
    }  
    int lockfd = open(pfile,O_RDWR);
    if (lockfd == -1)
    {  
        return -1;
    }  
    int iret = flock(lockfd,LOCK_EX|LOCK_NB);
    if (iret == -1)
    {  
        return -1;
    }   
    return 0;
}
posted @   J1nu  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示