flock
shell命令flock通過加鎖方式實現互斥訪問。常用于多進程間互斥訪問。flock用flock(2)系統調用實現。
Linux提供了flock(對整個文件加鎖)、fcntl(對整個文件區域加鎖)兩個函數來做進程間的文件同步。
同時也可以使用信號量來完成所需的同步,但通常使用文件鎖會更好一些,因為內核能夠自動將鎖與文件關聯起來。
flock 是對于整個文件的建議性鎖。也就是說,如果一個進程在一個文件(inode)上放了鎖,那么其它進程是可以知道的。(建議性鎖不強求進程遵守。)
最棒的一點是,flock(2)第一個參數是文件描述符,在此文件描述符關閉時,鎖會自動釋放。而當進程終止時,所有的文件描述符均會被關閉。于是,很多時候就不用考慮解鎖的事情。
用法
flock [-sxon] [-w timeout] lockfile [-c] command...
flock [-sxon] [-w timeout] lockdir [-c] command...
flock [-sxun] [-w timeout] fd
參數
-s: 獲取共享鎖,有時被稱為只讀鎖。在定向為某文件的FD上設置共享鎖而未釋放鎖的時間內,其他進程試圖在定向為此文件的FD上設置獨占鎖的請求失敗,而其他進程試圖在定向為此文件的FD上設置共享鎖的請求會成功。
-x,-e:獲取互斥鎖,有時稱為寫鎖,默認。在定向為某文件的FD上設置獨占鎖而未釋放鎖的時間內,其他進程試圖在定向為此文件的FD上設置共享鎖或獨占鎖都會失敗。
-u:釋放鎖。這個不是必須的,當文件關閉時(進程結束后,進程文件都被關閉)鎖被自動釋放。但是,特殊情況下是必須的,例如受鎖保護的命令行fork一個后臺進程,此進程不應該持有鎖。
Drop a lock. This is usually not required, since a lock is automatically dropped when the
file is closed. However, it may be required in special cases, for example if the enclosed
command group may have forked a background process which should not be holding the lock.
-n:非阻塞,獲取鎖失敗后立刻返回,退出碼1。
-w:seconds,等待超時。
-o:在執行命令前,關閉被鎖文件的文件描述符。這是有用的,當時命令行fork一個子進程,該子進程不應該持有鎖。
-c:傳遞一個單獨command給shell(在新shell進程中執行命令)。-c選項表示,如果成功鎖定,則執行其后用雙引號括起的命令,如果是多個命令,可以用分號分隔。
flock file -c command 等價于flock file sh -c command,前者flock用-c創建進程執行command,后者flock執行sh命令,sh命令創建進程執行命令command。
描述
該命令管理flock(2) locks為shell scripts或the command line。
第一或第二種形式在命令執行時回繞鎖。它鎖住指定文件或路徑(若不存在創建它)。
第三種形式在腳本中應用方便,形式如下
(
flock -n 9 || exit 1
# ... commands executed under lock ...
) 9>/var/lock/mylockfile
The mode used to open the file doesn't matter to flock; using > or >> allows the lockfile to be created if it does not already exist,however, write permission is required.
using < requires that the file already exists but only read permission is required.
默認情況下,flock會阻塞等,直到獲取鎖。
flock(2)中描述
Locks created by flock() are associated with an open file table entry. This means that duplicate
file descriptors (created by, for example, fork(2) or dup(2)) refer to the same lock, and this lock
may be modified or released using any of these descriptors. Furthermore, the lock is released
either by an explicit LOCK_UN operation on any of these duplicate descriptors, or when all such
descriptors have been closed.
如果通過一個特定的文件描述符獲取了一個鎖并且創建了該描述符的一個或多個副本,那么,如果不顯示的調用一個解鎖操作,只有當文件描述符副本都被關閉了之后鎖才會被釋放。
通過fork()創建的鎖在exec()中會得以保留(除非在文件描述符上設置了close-on-exec標記并且該文件描述符是最后一個引用底層的打開文件描述的描述符)。
應用
1 crontab運用flock防止重復執行
* * * * * (flock -xn ./test.lock -c "sh /root/test.sh") #-n 為非阻塞模式
2 機器down機自動啟動或重啟
可以在daemon開始的時候, 打開一個文件然后獲取一個寫鎖. 守護腳本也打開文件并設置寫鎖, 然后阻塞, 一旦寫鎖獲得成功, 則說明daemon已經掛了. 此時守護腳本重啟daemon并放棄寫鎖.
flock -x ./test.lock -c "/usr/local/nginx/sbin/nginx" #去掉-n表示使用阻塞模式
運行中... 再次執行
flock -x ./test.lock -c "/usr/local/nginx/sbin/nginx" #去掉-n表示使用阻塞模式
阻塞中...
模擬down機
[root@localhost ~]# ps aux |grep "nginx"|grep"master"|grep -v "grep"|awk'{print $2}'|xargskill -9
kill后阻塞的命令馬上執行 新的進程PID立馬產生。
3. flock執行多條命令
#!/bin/sh echo "pid is $$" flock wang sh -c " echo $$ ; while [ 1 ] ; do echo wangt ; echo $$ ; sleep 1; done ; " echo "exec over" exit 0
該進程執行會產生同時存在的三個進程:1)腳本本身啟動進程;2)執行flock時,flock語句本身作為子進程運行,父進程阻塞等待flock進程結束;
3)flock的參數sh開啟一個子進程執行后面的命令(有無sh都會開啟新進程執行命令)。
1)進程阻塞等待2)進程;2)進程阻塞等待3)進程;3)進程永不退出,所以一直打印進程號(注意,打印的進程號為1)進程號,即$$都為1)進程號),不會打印“exec over”。
若此時該腳本再被調用執行,則會同時再出現兩個進程:1)和2),進程2)忙等文件鎖(獲取鎖后才執行后面的命令)。
flock第三種形式應用
flock可以接收文件描述符參數。這種方法在 shell 腳本里特別有用。比如如下代碼:
lockit () {
exec 7<>.lock
flock -n 7 || {
echo "Waiting for lock to release..."
flock 7
}
}
exec行打開.lock文件為7號文件描述符,然后拿 flock 嘗試鎖它。如果失敗了,就輸出一條消息,并且等待鎖被釋放。那個7號文件描述符就讓它一直開著了,反正腳本執行完畢內核會釋放,也不用去調用trap內建命令了。
上邊有一點很有意思的是,flock 是一個子進程,但是因為文件描述符在 fork 和 execve 中會共享,而 flock 鎖在 fork 和 execve 時也不會改變,所以子進程在那個文件描述符上加鎖后,即使它退出了,因為那個文件描述符父進程還有一份,所以不會被關閉,鎖也就得以保留。(所以,如果余下的腳本里要是有進程帶著那個文件描述符fork 到后臺鎖就不會在腳本執行完后自動解除啦……)
----鎖不會被釋放
#!/bin/bash
{
flock –n 3
[$? –eq 1] && { echo fail ;exit}
echo succeed
#Doyour task here …
} 3 <> mylockfile
首先使用<>打開mylockfile 并定向到文件描述符3,而定向文件描述符是先于命令執行的,因此假如要執行的語句段中需要讀寫mylockfile文件,例如想獲得上一個腳本實例的 pid,并將此次的腳本實例的pid寫入mylockfile。此時直接用>打開mylockfile會清空上次存入的內容,而用<打開 mylockfile當它不存在時會導致一個錯誤。
其次,以非阻塞的方式打開mylockfile,flock –n 3,其中3是mylockfile的文件描述符,若能夠正常獲取鎖(默認是排它鎖),則繼續往下執行,否則返回1,該返回碼能夠在接下來的語句中[ $? –eq 1 ] 進行判斷,若為1,則輸出失敗并退出當前腳本。
參考:
1. flock——Linux 下的文件鎖
2. 每天進步一點點——Linux編程中的文件鎖之flock
3. 從flock引發的一個bug談起(1) 進程的文件描述符
總結
- 上一篇: 添加自签发的 SSL 证书为受信任的根证
- 下一篇: python自定义函数拟合