天天看點

eclipse同時運作兩個程式_如何讓你的程式同時隻能運作一個?

作者: 守望,Linux應用開發者,目前在公衆号【程式設計珠玑】 分享Linux/C/C++/資料結構與算法/工具等原創技術文章和學習資源。
eclipse同時運作兩個程式_如何讓你的程式同時隻能運作一個?

有些程式我們希望在一台機器上隻有一個執行個體在運作,我在windows下也遇到過很多類似這樣的程式,如QQ,它隻允許同時運作一個。那麼我們在Linux該如何實作這樣的單例運作的程式呢?

思路

實作這樣的程式方法很多,但是總體思路都是類似的:

  • 1.啟動程式,檢測标志,判斷是否有同樣的程式運作,是則2,否則3
  • 2.程式退出
  • 3.程式啟動,并設定标志,以便下次啟動時檢測

實作方法

按照這種思路,實作的方法有很多種,例如使用ps等指令擷取該程序的程序數,大于0 表示已有運作;啟動後寫一個臨時檔案,如果下次啟動時發現有該檔案,則直接退出;建立一個檔案并加鎖,退出時删除檔案,新的程式啟動時試圖加鎖,如果失敗,則說明已有執行個體運作…… 除了上面說到的這些,可能還有一些其他的實際做法,但是本文介紹一種實用并且也是非常通用的做法,即檔案鎖的方法。

基本原理

程式在啟動後,打開一個program.pid檔案(無則建立),然後試圖去設定檔案鎖(如果還不了解鎖的概念,可以簡單了解為,一旦a寫鎖定了,b就無法進一步寫操作了,除非a釋放鎖),如果設定成功,就将該程式的程序ID寫入該檔案;如果加鎖失敗,那麼說明已經有另外一個執行個體在運作了,則退出此次啟動。而目前已經運作的程式如果退出了,該檔案會自動解除鎖定。 實際上,我們觀察一下/var/run/目錄下,有很多類似這樣的檔案:

$ ls -l /var/run/*.pid-rw-r--r-- 1 root root 5 11月 24 08:19 /var/run/acpid.pid-rw-r--r-- 1 root root 5 11月 24 08:19 /var/run/atd.pid-rw-r--r-- 1 root root 5 11月 24 08:19 /var/run/crond.pid-rw-r--r-- 1 root root 5 11月 24 09:08 /var/run/dhclient-wlp3s0.pid-rw-r--r-- 1 root root 4 11月 24 08:19 /var/run/docker.pid           

不過這個位置通常隻有root使用者能夠寫入。

實作

在看代碼實作之前,先看下檔案鎖(記錄鎖)和fcntl函數。 flock結構至少包含以下字段 :

struct flock {    short l_type; /*鎖類型 F_RDLCK,F_WRLCK, F_UNLCK*/    short l_whence;  /* 偏移開始的位置 SEEK_SET, SEEK_CUR, SEEK_END */    off_t l_start;   /* 開始鎖定區域*/    off_t l_len;     /* 鎖定位元組數 */    pid_t l_pid;     /* 記錄鎖的程序ID*/};           

從結構體成員可以看到,它不僅可以鎖整個檔案,還可以鎖某個區域,但是本文僅用于鎖定整個檔案。

int fcntl(int fd, int cmd, ... /* arg */            

fcntl函數的cmd選項也很多,本文隻用到F_SETLK(或F_SETLKW,),即設定鎖。 結合以上兩者,參考代碼如下:

//來源:公衆号【程式設計珠玑】//部落格:https://www.yanbinghu.com#include #include #include #include #include #include #include #define PROC_NAME "single_instance"#define PID_FILE_PATH "/var/run/"static int lockFile(int fd);static int isRunning(const char *procname);int main(void){    /*判斷是否已經有執行個體在運作*/    if(isRunning(PROC_NAME))    {        exit(-1);    }    printf("run ok
");    sleep(20);//避免程式立即退出    return 0;}/*鎖檔案還可以使用flock,目的是類似的。不過是它是BSD系統調用,并且某些版本不支援NFS,出于移植性考慮,使用fcntl*/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;    fl.l_pid = -1;//鎖定檔案,設定為-1    return(fcntl(fd, F_SETLK, &fl));}static int isRunning(const char *procname){    char buf[16] = {0};    char filename[128] = {0};    sprintf(filename, "%s%s.pid",PID_FILE_PATH,procname);    int fd = open(filename, O_CREAT|O_RDWR );//可讀可寫,不存在時建立    if (fd 0) {        printf("open file %s failed!
", filename);        return 1;    }    if (-1 == lockFile(fd)) /*嘗試加鎖*/    {                                                          printf("%s is already running
", procname);        close(fd);        return 1;    }     else     {        ftruncate(fd, 0);/*截斷檔案,重新寫入pid*/        sprintf(buf, "%ld", (long)getpid());        write(fd, buf, strlen(buf) + 1);        return 0;    }}           

編譯運作

$ gcc -o single_instance single_instance.c$ ./single_instance  #注意root權限運作,或者調整pid檔案位置run ok           

檢視pid檔案目錄下已經有了pidfile:

$ ls -al /var/run/single_instance.pid-rw-r--r-- 1 root root 6 11月 24 11:36 /var/run/single_instance.pid           

在另外一個終端再次嘗試運作:

$ ./single_instancesingle_instance is already running           

如果你想控制同一個目錄下的bin檔案隻能運作一個,那麼可以設定pid檔案的位置為目前目錄。 這種方式有什麼特點呢:

  • 簡單可靠
  • 可讀可見,相比于信号量或共享記憶體,它更容易觀察
  • 無性能要求,啟動時加鎖,結束釋放。
  • 一旦出現異常沒有釋放,也可以手動删除檔案

當然對于BSD系統,還可以使用下面的接口來完成:

 struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr);int pidfile_write(struct pidfh *pfh);int pidfile_close(struct pidfh *pfh);int pidfile_remove(struct pidfh *pfh);           

本文就不過多介紹了。

總結

單例運作的基本原理是類似的,而pid檔案是一種常見的單例運作的方式,很多知名的開源元件都是使用類似的方式。對于shell腳本,還可以使用flock指令進行類似的操作。 你一般用什麼方式來實作單例運作呢?歡迎留言分享。

●編号618,輸入編号直達本文

●輸入m擷取文章目錄

C語言與C++程式設計

eclipse同時運作兩個程式_如何讓你的程式同時隻能運作一個?

分享C/C++技術文章