生活随笔
收集整理的這篇文章主要介紹了
linux下程序如何实现单实例运行
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1、技術原理
無論是windows還是linux下,程序設計者都會遇到一個問題,那就是如何實現程序的單實例運行。比如,Windows自帶的播放軟件Windows Medea Player只能啟動一個實例。原因很簡單,如果同時啟動幾個實例,卻播放不同的文件,那么聲音和圖像就會引起混亂。所以,我們要做的就是,程序啟動時檢測一下系統中是否已經存在一個完全一樣的實例,如果已經存在,則本次啟動的程序自動退出。那么,從編碼的角度來分析,該如何實現這個效果呢?在linux系統中,我們一般有以下幾種方法:
shell使用ps命令來判斷。最常見也是最簡單的方案,直接寫一個特定的shell腳本來實現。不過存在可移植性差的問題,進程名字一旦改變之后,腳本就失去作用無法監控。同時,還要額外附加這個腳本文件在系統中運行,實在有點多余;信號量/共享內存。使用共享內存,通過shmget操作共享內存,然后寫入pid,這樣就不用生成可見的文件。這個方案只存在一個很小的缺陷,需要配置共享內存的key,并保證不與系統其他應用沖突,一般來說,沖突概率非常小;端口搶占。應用于大多數的Linux網絡應用。思路是系統保證每個端口的TCP只能有一個進程監聽,那么如果程序啟動時,監聽一個核心的端口,第二個運行的實例就會監聽失敗,無法啟動。這個方案同樣很有效,省去了一個額外的配置文件,不足之處是一般只用于帶網絡的程序;創建文件,加鎖(建議性鎖)。這種做法最常見了,應用于大多數的Linux程序,如apache httpd, mysql。思路是配置一個pid文件,當程序啟動時,對pid文件加鎖,然后寫入本進程的pid,如果鎖失敗,說明有實例已經啟動了。這個方案非常可靠,唯一的不足是需要配置一個pid文件,并且保證文件目錄和文件可寫;進程列表檢測。對于運維常用的方法。由于運維不一定能控制程序的修改,所以考慮從外部解決。crontab腳本,查詢運行的進程數,一旦發現進程數與預期不符,那么killall,重啟進程。這個方案是旁路方案,比上面的方式更通用,還可以監視進程數,避免某些子進程core。這個方案沒有什么缺陷,如果硬要找一個的話,不同的系統ps命令輸出可能不一樣,腳本需要考慮移植。
2、源碼實現
經過一番對比,優選其中的方案4,也是最大眾化的一個方案。下面就是詳細的代碼實現:
#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>
static int lockfile(
int fd)
{
struct flock fl;fl.l_type = F_WRLCK;fl.l_start =
0;fl.l_whence = SEEK_SET;fl.l_len =
0;
return(fcntl(fd, F_SETLK, &fl));
}
int proc_is_exist(
const char *procname)
{
int fd;
char buf[
16];
char filename[
100];
sprintf(filename,
"/var/run/%s.pid", procname);fd = open(filename, O_RDWR | O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
if (fd <
0) {
printf(
"open file \"%s\" failed!!!\n", filename);
return 1;}
if (lockfile(fd) == -
1) {
printf(
"file \"%s\" locked. proc already exit!!!\n", filename);close(fd);
return 1;}
else {ftruncate(fd,
0);
sprintf(buf,
"%ld", (
long)getpid());write(fd, buf,
strlen(buf) +
1);
return 0;}
}
#ifndef SINGLE_INSTANCE_H
#define SINGLE_INSTANCE_H#ifdef __cplusplus
extern "C"
{
#endifint proc_is_exist(
const char *procname);
#ifdef __cplusplus
}
#endif#endif
3、使用說明
調用者只需在程序啟動時調用本函數,根據返回值進行判斷即可:
if (proc_is_exist(g_fk_process_name) == TRUE) { print_sys(
"an \"%s\" already running in system. exit now...\n", g_fk_process_name);
return 0;
}
else {print_sys(
"\"%s\" starting...\n", g_fk_process_name);
}
總結
以上是生活随笔為你收集整理的linux下程序如何实现单实例运行的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。