【指令碼】如何確保應用程式的唯一性

楊奇龍發表於2016-05-31
簡介
    相信大家在開發指令碼或者寫程式的時候 ,大多會遇到如何判斷已經有程式在執行的情況。比如設計備份binlog ,由於某個例項產生的binlog 數量大於備份的速度,在下一個時間點,會啟動一個新的程式對binlog進行備份。那我們要怎麼解決呢,本文分別從 shell和python的角度提出我的解決方法,同時也推薦《 Ensure a single instance of an application in Linux》,這裡有比較詳細的討論。
一  shell 指令碼的解決方法
利用mkdir 的特性 建立已經存在的檔案目錄則會失敗。程式第一次執行的時候可以建立一個 /tmp/lock資料夾,標示當前已經執行一個程式,當啟動第二個程式時,mkdir /tmp/lock 便會失敗。
  1. #!/bin/bash
  2. mkdir /tmp/lock
  3. if [ $? -ne 0 ];then
  4.    echo "there is tr script running .. "
  5.    exit 1
  6. fi
  7. trap "rm -fr /tmp/lock " SIGINT SIGTERM
  8. sleep 50
  9. if [ -d /tmp/lock ];then
  10.    rm -fr /tmp/lock
  11.    echo "rm -fr /tmp/lock"
  12. fi
注意 linux中的trap命令是防止指令碼異常終止 :被kill (不是kill -9) ,crtl+c 中斷 比較詳細的資料 《Linux命令之trap - 在指令碼中處理訊號》http://codingstandards.iteye.com/blog/836588

二  python 指令碼的解決方法
網上搜尋python 鎖定檔案的時候,都會提示 fcntl 模組。Python的檔案鎖目前使用的是fcntl這個庫,它實際上為 Unix上的ioctl,flock和fcntl 函式提供了一個介面。
fcntl模組的函式flock(file_handle, operation)
其中 file_handle 表示檔案描述符,operation 指要進行的鎖操作,有如下幾種:
fcntl.LOCK_UN  解鎖:刪除floc()函式建立的鎖
fcntl.LOCK_EX  排他鎖:除加鎖程式外其他程式沒有對已加鎖檔案讀寫訪問許可權。
fcntl.LOCK_SH  共享鎖:所有程式沒有寫訪問許可權,即使是加鎖程式也沒有。所有程式有讀訪問許可權。
fcntl.LOCK_NB  非阻塞鎖: 此引數意味著函式不能獲得檔案鎖就立即返回,否則,如果使用LOCK_EX/LOCK_SH請求加鎖不成功,則當前程式會等待獲得檔案鎖。使用LOCK_NB可以在獲得這個排他鎖的情況下不阻塞該程式,LOCK_NB 也可以同LOCK_SH或LOCK_NB進行按位或(|)運算操作,比如fcnt.flock(file_handle,fcntl.LOCK_EX|fcntl.LOCK_NB),此時系統便不會阻塞當前的程式。
注意:
  1. 對於檔案的f.close() 操作會使檔案鎖失效;
  2. 主程式結束後檔案鎖失效;
  3. flock()的LOCK_EX是"勸告鎖",系統核心不會強制檢查鎖的狀態,需要在程式碼中進行檔案操作的地方顯式檢查才能生效。
測試指令碼
指令碼中使用is_running 函式對檔案加鎖,time.sleep(10) 模擬長時間執行的程式,第一次執行lock.py 成功加鎖,在程式執行期間 再次執行lock.py ,獲取鎖時會失敗,並且及時退出程式。
  1. #!/usr/bin/python2.6
  2. #coding:utf8
  3. import time
  4. import fcntl
  5. import sys
  6. def is_running(file):
  7.     lock_file=open(file,"w")
  8.     try:
  9.         fcntl.lockf(lock_file,fcntl.LOCK_EX|fcntl.LOCK_NB)
  10.         print "給檔案加鎖 ,請等待10s..."
  11.     except :
  12.         print '檔案加鎖,無法執行,請稍後執行。'
  13.         return None
  14.     return lock_file

  15. if __name__ == "__main__":
  16.     lockfile="/tmp/rsync_is_running"
  17.     a=is_running(lockfile)
  18.     if a is None :
  19.       print "lock file failed , rsync is running .quit ..."
  20.       sys.exit(0)
  21.     else :
  22.       print "lock file successed !!! "
  23.     time.sleep(10)
測試例子:
會話一

會話二


三  小結
    其實還可以有很多其他的方式 比如 最容易想到的 application_name.pid 或者ps  application_name | wc -l 來判斷,不過使用ps 命令時,遇到和系統其他命令關鍵字一樣的時候 ,就會不準。http://stackoverflow.com/中比較推薦使用pid ,各位讀者朋友也可以提出自己的見解。歡迎討論。




來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22664653/viewspace-2110638/,如需轉載,請註明出處,否則將追究法律責任。

相關文章