天天看點

如何保證隻有一個程序執行個體

作者:[email protected]

部落格:blog.focus-linux.net   linuxfocus.blog.chinaunix.net 

微網誌:weibo.com/glinuxer

QQ技術群:4367710

本文的copyleft歸[email protected]所有,使用GPL釋出,可以自由拷貝,轉載。但轉載請保持文檔的完整性,注明原作者及原連結,嚴禁用于任何商業用途。

============================================================================================================================

在編寫服務程序的時候,經常有這樣一個需求:保證服務程序隻有一個執行個體在運作。

為實作這個簡單的功能,有下面各種常見的實作方式:

1. 通過已知的程序名,來查詢是否有同名的程序正在運作。

   可以利用proc,也可以讀取ps的輸出等;

2. 利用pid檔案,這也是linux各種服務常見的實作方式:    

    服務程序啟動的時候,首先在指定目錄下,一般為/var/run/,查找是否已經存在對應該程序的pid檔案。

   如果已經存在,表明有同樣的程序在運作。但是也許該程序意外崩潰,是以需要進一步檢查。讀取該pid檔案,獲得pid。

   然後再利用确定該pid的程序是否存在。如存在,是否為同名程序。

上面兩種方式,是我以前常用的方法。後來,我更傾向于下面這種利用flock檔案鎖的方式。

閑話不說,見代碼:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <errno.h>

#include <sys/file.h>

#include <unistd.h>

#include <my_basetype.h>

static int g_single_proc_inst_lock_fd = -1;

static void single_proc_inst_lockfile_cleanup(void)

{

    if (g_single_proc_inst_lock_fd != -1) {

        close(g_single_proc_inst_lock_fd);

        g_single_proc_inst_lock_fd = -1;

    }

}

B_BOOL is_single_proc_inst_running(const char *process_name)

    char lock_file[128];

    snprintf(lock_file, sizeof(lock_file), "/var/tmp/%s.lock", process_name);

    g_single_proc_inst_lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644);

    if (-1 == g_single_proc_inst_lock_fd) {

        fprintf(stderr, "Fail to open lock file(%s). Error: %s\n",

            lock_file, strerror(errno));

        return B_FALSE;

    if (0 == flock(g_single_proc_inst_lock_fd, LOCK_EX | LOCK_NB)) {

        atexit(single_proc_inst_lockfile_cleanup);

        return B_TRUE;

    close(g_single_proc_inst_lock_fd);

    g_single_proc_inst_lock_fd = -1;

    return B_FALSE;

注:這個代碼由我自定義的類型,如B_BOOL。感興趣的同學,可以自行更改。

is_single_proc_inst_running為關鍵函數,傳回true,則表明隻有一個程序執行個體在運作(本程序)。傳回false則表明已有同名程序在運作了。

利用非阻塞的檔案鎖,對相應的檔案進行上鎖。成功獲得檔案鎖的時候,就排斥了其它執行個體再次拿鎖。在程序退出時,無論是正常退出還是意外崩潰的時候,Linux核心本身都會關閉該檔案描述符。

當檔案關閉時,檔案鎖都會被釋放。這樣新的服務程序可以再次啟動。

但是我在寫這個代碼時,還是利用atexit,實作了對該檔案描述符的關閉。即使加了這個不必要的實作,這份代碼仍然比最早提出的兩種方式要簡單的多。

這份代碼沒有考慮多線程競争,因為沒有必要。一般來說,檢測程序唯一執行個體應該是在程序剛剛啟動的時候。那時,應該隻有一個線程。

希望大家對這個實作提意見,或者分享你的方法。

繼續閱讀