部落格: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,實作了對該檔案描述符的關閉。即使加了這個不必要的實作,這份代碼仍然比最早提出的兩種方式要簡單的多。
這份代碼沒有考慮多線程競争,因為沒有必要。一般來說,檢測程序唯一執行個體應該是在程序剛剛啟動的時候。那時,應該隻有一個線程。
希望大家對這個實作提意見,或者分享你的方法。