linux下C程序:運行單個實例

對於不少服務來講,在同一個服務器上只能運行一個實例,那麼經過什麼方法來保證程序同一時刻只有一個實例運行呢?經過編寫shell腳原本管理程序的啓動、中止是個不錯的方法。在啓動時,shell腳本會建立進程標識文件(存儲正在運行實例的pid)以代表已經有實例在運行,若是文件已存在,則說明已有實例在運行,不須要作任何事;在退出時,shell腳本會刪除進程標識文件,代表沒有實例運行。shell

shell腳本管理方法在應用程序之上再包了一層,那麼能不能直接在程序開始運行時本身判斷是否有實例在運行呢,答案是確定的。原理其實差很少,仍是要藉助公用資源---文件,固然不單單是文件而已,還須要文件鎖的支持。大體思路是這樣的:程序在開始運行時對特定文件進行加鎖(不存在則建立),若是加鎖成功,則實例開始運行;如鎖已經被佔有,則說明已經有實例在運行,則程序直接退出;另外在實例運行完畢後對文件的鎖也隨着丟掉了。這樣就能保證每次只有一個程序實例在運行。服務器

具體步驟以下:code

1. 打開特定文件(如/var/run/mydaemon.pid),如不存在則建立之;
2. 使用fcntl對文件整個區域加勸告鎖;
3. 若是加鎖成功,則繼續執行後續代碼,並將pid寫入文件;如加鎖不成功,說明已經有實例在運行,直接退出。進程

t1.c資源

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <printf.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#define LOCKFILE "/var/run/mydaemon.pid"
#define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

/* set advisory lock on file */
int lockfile(int fd)
{
        struct flock fl;
 
        fl.l_type = F_WRLCK;  /* write lock */
        fl.l_start = 0;
        fl.l_whence = SEEK_SET;
        fl.l_len = 0;  //lock the whole file
 
        return(fcntl(fd, F_SETLK, &fl));
}

int already_running(const char *filename)
{
        int fd;
        char buf[16];
 
        fd = open(filename, O_RDWR | O_CREAT, LOCKMODE);
        if (fd < 0) {
                printf("can't open %s: %m\n", filename);
                exit(1);
        }
 
        /* 先獲取文件鎖 */
        if (lockfile(fd) == -1) {
                if (errno == EACCES || errno == EAGAIN) {
                        printf("file: %s already locked\n", filename);
                        close(fd);
                        return 1;
                }
                printf("can't lock %s: %m\n", filename);
                exit(1);
        }
        /* 寫入運行實例的pid */
        ftruncate(fd, 0);
        sprintf(buf, "%ld\n", (long)getpid());
        write(fd, buf, strlen(buf) + 1);
        return 0;
}

int main(int argc, char *argv[])
{
        if (already_running(LOCKFILE))
                return 0;
        /* 在這裏添加工做代碼 */
        printf("start main...\n");
        sleep(100);
        printf("main done!\n");
        exit(0);
}

 

結果:get

編譯運行string

查看pid文件中的進程號it

再次運行第二次io

失敗的, 只有第一個進程再運行。編譯

相關文章
相關標籤/搜索