### 進程鎖
這里的進程鎖與線程鎖、互斥量、讀寫鎖和自旋鎖不同,它是通過記錄一個PID文件,避免兩個進程同時運行的文件鎖。
進程鎖的作用之一就是可以協調進程的運行,例如[crontab使用進程鎖解決沖突](http://www.live-in.org/archives/1036.html)提到,使用crontab限定每一分鐘執行一個任務,但這個進程運行時間可能超過一分鐘,如果不用進程鎖解決沖突的話兩個進程一起執行就會有問題。后面提到的項目實例Run也有類似的問題,通過進程鎖可以解決進程間同步的問題。
使用PID文件鎖還有一個好處,方便進程向自己發停止或者重啟信號。Nginx編譯時可指定參數`--pid-path=/var/run/nginx.pid`,進程起來后就會把當前的PID寫入這個文件,當然如果這個文件已經存在了,也就是前一個進程還沒有退出,那么Nginx就不會重新啟動。進程管理工具Supervisord也是通過記錄進程的PID來停止或者拉起它監控的進程的。
### 使用進程鎖
進程鎖在特定場景是非常適用的,而操作系統默認不會為每個程序創建進程鎖,那我們該如何使用呢?
其實要實現一個進程鎖很簡單,通過文件就可以實現了。例如程序開始運行時去檢查一個PID文件,如果文件存在就直接退出,如果文件不存在就創建一個,并把當前進程的PID寫入文件中。這樣我們很容易可以實和讀鎖,但是所有流程都需要自己控制。
當然根據DRY(Don't Repeat Yourself)原則,Linux已經為我們提供了`flock`接口。
### 使用Flock
Flock提供的是advisory lock,也就是建議性的鎖,其他進程實際上也可以讀寫這個鎖文件。Linux上可以直接使用`flock`命令,使用C可以調用原生的`flock`接口,這里詳細介紹Go 1.3引入的`FcntlFock()`。
我們封裝了簡單的接口。
~~~
// Control the lock of file.
func fcntlFlock(lockType int16, path ...string) error {
var err error
if lockType != syscall.F_UNLCK {
mode := syscall.O_CREAT | syscall.O_WRONLY
lockFile, err = os.OpenFile(path[0], mode, 0666)
if err != nil {
return err
}
}
lock := syscall.Flock_t{
Start: 0,
Len: 1,
Type: lockType,
Whence: int16(os.SEEK_SET),
}
return syscall.FcntlFlock(lockFile.Fd(), syscall.F_SETLK, &lock)
}
~~~
這樣對進程加鎖。
~~~
// Lock the file.
func Flock(path string) error {
return fcntlFlock(syscall.F_WRLCK, path)
}
~~~
這樣對進程解鎖。
~~~
// Unlock the file.
func Funlock(path string) error {
err := fcntlFlock(syscall.F_UNLCK)
if err != nil {
return err
} else {
return lockFile.Close()
}
}
~~~
學習完進程鎖,我們開始了解各種進程,如孤兒進程、僵尸進程。
- 前言
- 致謝
- 概述
- 使用代碼
- 使用Docker
- 進程基礎
- 進程是什么
- Hello World
- PID
- PPID
- 使用PID
- 進程名字
- 進程參數
- 輸入與輸出
- 并發與并行
- 進程越多越好
- 進程狀態
- 退出碼
- 進程資源
- 死鎖
- 活鎖
- POSIX
- Nohup
- 運行進程
- Go編程實例
- 衍生新進程
- 執行外部程序
- 復制進程
- 進程進階
- 文件鎖
- 孤兒進程
- 僵尸進程
- 守護進程
- 進程間通信
- 信號
- Linux系統調用
- 文件描述符
- Epoll
- 共享內存
- Copy On Write
- Cgroups
- Namespaces
- 項目實例Run
- 項目架構
- 代碼實現
- 注意事項
- 創建目錄權限
- 捕獲SIGKILL
- Sendfile系統調用
- 后記
- 參考書籍
- 項目學習
- 再次感謝