目錄
- 前言
- flock命令
- 命令介紹
- flock實體
- 代碼實作
- 獲取檔案鎖
- 檔案鎖判斷單例
- tcp埠判斷單例
- 創建互斥體實作單例
- 總結
前言
很多時候我們都需要行程單例運行,當再次運行程式時檢查到已有程式在運行可以做特別的操作,比如置頂已運行的程式,比如當前程式提示一下就退出,
最簡單方案是打開行程創建一個檔案,程式結束時洗掉檔案,當第二個程式運行時判斷該檔案存在則認為已有程式運行,問題是程式例外退出沒有洗掉那個檔案就GG了,
還有方案就是行程啟動時鎖住一個檔案,行程退出釋放鎖,行程例外退出由系統自動釋放鎖,這個就是完美的方案,
還有一種方案就是判斷行程名是否允許,Linux下可以執行【ps auxf | grep xxx】,Windows下可以執行【tasklist | findstr xxx】,問題就是程式檔案名被改就GG,
另外還可以監聽一個tcp埠,如果第二個行程運行也監聽相同埠會報錯,因此也能實作行程單例運行,只是需要占用一個埠,
在win平臺下還可以通過創建一個互斥體實作行程單例,
flock命令
命令介紹
該工具是用來獲取一個檔案鎖,并執行命令,當檔案已經被鎖則不會執行命令,使用該命令可有效防止重復執行一些操作,特別是cron腳本,由于腳本執行周期長,下一次定時執行又到了,可以不重復執行,
Windows下也是可以安裝flock命令的,我是安裝【msys2】后默認就有了,下面看下該工具的幫助檔案:
flock -h
Usage:
flock [options] <file>|<directory> <command> [<argument>...]
flock [options] <file>|<directory> -c <command>
flock [options] <file descriptor number>
Manage file locks from shell scripts.
Options:
-s, --shared get a shared lock // 獲取讀鎖(共享鎖),多個行程可獲取并讀檔案,其他行程獲取寫鎖會回傳失敗
-x, --exclusive get an exclusive lock (default) // 獲取寫鎖(排它鎖),只允許一個行程獲取,其他行程獲取均回傳失敗
-u, --unlock remove a lock
-n, --nonblock fail rather than wait // 當獲取鎖失敗時直接回傳,不帶此選項程式會卡住,直到獲取到鎖
-w, --timeout <secs> wait for a limited amount of time // 獲取鎖超時的時間
-E, --conflict-exit-code <number> exit code after conflict or timeout // 當獲取鎖失敗時,回傳的錯誤碼.在Linux執行【echo $?】,win執行【echo %errorlevel%】查看
-o, --close close file descriptor before running command
-c, --command <command> run a single command string through the shell // 鎖住檔案的同時執行一個命令,我一般用來執行一個腳本
--verbose increase verbosity
-h, --help display this help and exit
-V, --version output version information and exit
For more details see flock(1).
flock實體

代碼實作
獲取檔案鎖
可以執行
go get github.com/jan-bar/golibs,下載我寫好的庫,關于Windows和Linux下獲取檔案鎖和釋放檔案鎖,
下面的代碼,同時執行2個行程會回傳錯誤file is lock,請看示例程式:
package main
import (
"os"
"strconv"
"time"
"github.com/jan-bar/golibs/filelock"
)
func main() {
fr, err := filelock.LockOpenFile("a.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666, filelock.WriteLock)
if err != nil {
panic(err)
}
defer fr.Close()
fr.File.Write([]byte(strconv.Itoa(os.Getpid())))
time.Sleep(time.Second * 5)
}
檔案鎖判斷單例
可以根據回傳錯誤值判斷檔案是否被鎖住,如果鎖住就認為已有行程在執行,
package main
import (
"fmt"
"github.com/jan-bar/golibs"
)
func main() {
err := golibs.SingletonFile("a.txt")
if err == golibs.ErrSingleton {
fmt.Println("已有行程在運行")
}
}
tcp埠判斷單例
如果本機指定埠已經被監聽,則證明已有程式在運行,
package main
import (
"fmt"
"github.com/jan-bar/golibs"
)
func main() {
err := golibs.SingletonTcp(8080)
if err == golibs.ErrSingleton {
fmt.Println("已有行程在運行")
}
}
創建互斥體實作單例
原理是使用win32api中的
CreateMutexW創建一個互斥體,多個行程都創建同名互斥體時如果已有行程先創建后面的行程會提示已存在,
package main
import (
"fmt"
"github.com/jan-bar/golibs"
)
func main() {
err := golibs.SingletonWin("process")
fmt.Println(err)
fmt.Scanln()
}
總結
????行程單例運行在很多場景都是有必要的,上面介紹的幾種方案,我比較喜歡通過加鎖檔案來判斷行程是否已經被運行過,因為只占用一個檔案,很多工具都是通過鎖檔案,并將自己的pid寫入檔案,方便其他操作去讀取這個行程的pid,而不用通過ps去查詢,堪稱完美,我只測驗了Windows和Linux下的檔案鎖功能,Windows是使用win32api去實作,Linux是系統自帶的介面,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/195991.html
標籤:其他
上一篇:docker 練習第一天
