golang下文件鎖的使用

2021-02-13 碼農的自由之路
前言

題目是golang下文件鎖的使用,但本文的目的其實是通過golang下的文件鎖的使用方法,來一窺文件鎖背後的機制。

為什麼需要文件鎖

只有多線程/多進程這種並發場景下讀寫文件,才需要加鎖,

場景1-讀寫並發

讀寫並發場景下,如果不加鎖,就會出現讀到髒數據的情況。想像一下,讀文件的進程,讀到第500位元組,有其它進程以覆蓋寫的方式向文件中寫入1000位元組,那讀進程讀到的後500位元組就是髒數據。

場景2-寫寫並發

寫寫並發場景下,如果不加鎖,假設A進程先寫0-1000位元組,B進程寫0-900位元組,以此類推,最後一個進程寫0-100位元組,那最終的文件內容就是每個進程前100個字節拼接起來的錯亂的內容了。

文件鎖的幾個概念

共享鎖

共享鎖,也叫讀鎖。某個進程首次獲取共享鎖後,會生成一個鎖類型的變量L,類型標記為共享鎖。其它進程獲取讀鎖的時候,L中的計數器加1,表示又有一個進程獲取到了共享鎖。這個時候如果有進程來獲取排它鎖,會獲取失敗。

排它鎖

排它鎖,也叫寫鎖。某個進程首次獲取排他鎖後,會生成一個鎖類型的變量L,類型標記為排他鎖。其它進程獲取任何類型的鎖的時候,都會獲取失敗。

阻塞

阻塞的意思是說,新的進程發現當前的文件(數據)被加鎖後,會一直處於等待狀態,直到鎖被釋放,才會繼續下一步的行為。

非阻塞

非阻塞的意思是說,新的進程發現當前的文件(數據)被加鎖後,立即返回異常。業務上需要根據具體的業務場景對該異常進行處理。

阻塞和非阻塞其實是進程遇到鎖的時候的兩種處理模式。

golang下如何使用文件鎖基本使用
package main
import ( "log" "os" "syscall")
func main() { f, err := os.Create("example.txt") if err != nil { log.Println("create file example.txt failed", err) } defer f.Close() if err := syscall.Flock(int(f.Fd()), syscall.LOCK_SH|syscall.LOCK_NB); err != nil { log.Println("add share lock in no block failed", err) }
if err := syscall.Flock(int(f.Fd()), syscall.LOCK_UN); err != nil { log.Println("unlock share lock failed", err) }
return}

示例中 LOCK_SH 表示當前獲取的是共享鎖,如果是 LOCK_EX,則表示獲取的是排他鎖。而 LOCK_NB 表示當前獲取鎖的模式是非阻塞模式,如果需要阻塞模式,不加這個參數即可。LOCK_UN 則表示解鎖,即釋放鎖。

golang 下這種文件鎖的使用方式其實是Linux下的系統級調用,使用的是Linux的原生的文件鎖的相關能力。

使用flock的幾個注意點

1、只要fd指向的是同一個文件指針,那麼加鎖解鎖的行為都是繼承和覆蓋的(這個可以看最後的解釋)。

2、flock這種方式加的是建議性鎖,也就是說新的進程一上來不管三七二十一,不去通過flock獲取鎖,就對文件各種操作,也是可以正常生效的。

說一說Linux下面的flock和fcntl

和flock一樣,fcntl也是系統級調用,但是在具體的使用上卻有很大不用,並且兩種鎖互不幹擾,用flock加鎖,fcntl無法感知,反之也一樣。

建議性鎖和強制鎖

flock加的是建議性鎖,而fcntl加的是強制性鎖。

建議性鎖,本質是一種協議,約定讀寫操作前都去檢查一下該文件是否有被其它進程加鎖。如果不遵守該協議,一上來就對文件進行操作,不檢查有沒有鎖,程序執行上是沒有任何問題的,能執行成功。

強制性鎖,才更像真正意義上的鎖。只要加了鎖,其它進程是無法執行非允許的操作的。

其實一些利用redis做的分布式鎖,都是建議性鎖。鎖機的機制要生效,需要大家共同遵守這個約定才行。

全局鎖和局部鎖

對於一個文件,flock加鎖的範圍是整個文件內容,而fcntl能對文件的任意部分加鎖。

鎖的持有者問題

flock認為,鎖的持有者是文件表(可以理解為文件指針),所以對於fork和dup操作,他們都對應同一個文件指針,所有的操作都會作用到這個文件上。具體表現:

fcntl 認為,鎖的持有者是進程。加鎖和解鎖的行為都是跟著進程走,具體表現為:

參考

[1] 被遺忘的桃源——flock 文件鎖

[2] Linux文件鎖學習-flock, lockf, fcntl

相關焦點

  • 使用Golang快速構建WEB應用
    如果發現問題或者有好的建議請回復我我回及時更正。 1.Abstract在學習web開發的過程中會遇到很多困難,因此寫了一篇類似綜述類的文章。作為路線圖從web開發要素的index出發來介紹golang開發的學習流程以及Example代碼。在描述中多是使用代碼來描述使用方法不會做過多的說明。最後可以方便的copy代碼來實現自己的需求。
  • 使用Golang操作文件的那些事兒
    例如咱們常見的文件後綴名.exe,.txt,'.word'…等等文件的基本操作可簡單分為增、刪兩類,也就是咱們所說的CURD(增刪改查),也是基於此兩類操作。可簡單理解為打開文件夾、CURD、關閉文件夾。結束~golang對於文件基本上都是基於Golang的os模塊,那讓我們一起了解一下,那麼Golang是如何對文件進行操作呢。
  • golang之context使用
    背景golang中並發編程的三種實現方式:chan管道、waitGroup和Context。本篇將重點介紹context的使用,告訴大家基本的使用方式,做到會用。Context概念介紹context譯為上下文,golang在1.6.2的時候還沒有自己的context,在1.7的版本中就把golang.org/x/net/context包被加入到了官方的庫中。golang 的 Context包,是專門用來處理多個goroutine之間與請求域的數據、取消信號、截止時間等相關操作。
  • Golang 性能分析工具簡要介紹
    這個環境變量,則需要到這個環境變量設置的地址中查找 profile 文件)可以通過 -base 參數來比較一下兩次 profile 文件是否有增長,使用如下命令:go tool pprof -base xxx/goroutine-test xxxx001.pb.gz xxxx002.pb.gzEntering interactive mode
  • Golang入門教程——基本操作篇
    比如當我們打開一個文件的時候,不管文件有沒有打開成功,我們都需要記得關閉文件。但如果文件打開不成功可能就會有異常或者是報錯,如果我們把這些情況全部都考慮到,會變得非常複雜。所以這個時候我們通常都會用defer來執行文件的關閉。要注意的是,defer修飾的代碼會被放入棧中。所以最後會按照先進後出的原則進行執行。
  • gRPC 實操指南(golang)
    •C/S架構的傳輸業務,如股票軟體,每天需要用戶登陸的時候去伺服器拉取最新的數據,或者較簡單的文件傳輸業務,登陸驗證業務,證書業務都可以使用rpc的方式•跨語言開發的項目,比如web業務使用golang進行開發,底層使用cpp或c,部分腳本使用py,跨語言通信可以通過RPC提供的不同語言的開發機制進行實現。
  • Golang語言標準庫 sync 包的 Once 怎麼使用?
    o.doSlow(f) }}func (o *Once) doSlow(f func()) {  // 二次檢查時,持有互斥鎖,保證只有一個 goroutine 執行。05總結本文開篇介紹了 Once 的官方定義和使用場景,然後結合示例代碼,介紹了 Once 的基本使用,並通過閱讀源碼,介紹了 Once 的實現原理,最後列舉了一個容易踩的「坑」。
  • GoHub 更新至 0.6,在線 Golang 文檔閱讀
    GoHub 使用 Github REST API v3 提供在線 Golang 文檔閱讀.支持兩種結構:Object 單個文檔項目, 多個 Package 組成Array 文檔項目列表, 每個項目的地址和說明, 每個項目下必須有 golist.json例: 單個文檔項目, 使用 GoDocu 生成.
  • Golang並發:再也不愁選channel還是選鎖
    借用《Golang並發的次優選擇:sync包》中銀行的例子,介紹如何使用channel解決例子中銀行的並發問題:銀行支持多個用戶的同時操作。順便看下同一個並發問題,使用channel和Mutex解決是什麼差別。一起分析下多個用戶同時操作銀行的數據流動:每個人都可以向銀行發起請求,請求可以是存、取、查3種操作,並且包含操作時必要的數據,包含的數據只和自身相關。
  • Golang入門教程——map篇
    今天是golang專題的第7篇文章,我們來聊聊golang當中map的用法。map這個數據結構我們經常使用,存儲的是key-value的鍵值對。在C++/java當中叫做map,在Python中叫做dict。
  • Java中的文件鎖到底是怎麼回事?
    本教程中, 我們將介紹使用 Java NIO 庫實現這一點的各種方法。# 文件鎖簡介「一般來說,有兩種鎖」:簡單地說,在寫操作完成時,獨佔鎖防止所有其他操作(包括讀操作)。相反,共享鎖允許多個進程同時讀取。讀鎖的目的是防止另一個進程獲取寫鎖。通常,處於一致狀態的文件確實應該被任何進程讀取。
  • Linux 編程中的文件鎖之 flock
    ,防止數據的不一致,這是最為普遍的使用方法。那在多進程中如何處理文件之間的同步呢?我們看看下面的圖:圖中所示的是兩個進程在無同步的情況下同時更新同一個文件的過程,其主要的操作是:1. 從文件中讀取序號。2. 使用這個序號完成應用程式定義的任務。3. 遞增這個序號並將其寫回文件中。
  • Golang指南:頂級Golang框架、IDE和工具列表
    (點擊尾部閱讀原文前往)原文:https://dzone.com/articles/golang-guide-a-list-of-top-golang-frameworks-ides自推出以來,Google的Go程式語言(Golang)越來越受主流用戶的歡迎。
  • Golang入門教程——面向對象篇
    golang作為一門剛剛誕生十年的新興語言自然是支持面向對象的,但是golang當中面向對象的概念和特性與我們之前熟悉的大部分語言都不盡相同。比如Java、Python等,相比之下, golang這個部分的設計非常得簡潔和優雅(仁者見仁),所以即使你之前沒有系統地了解過面向對象,也沒有關係,也一定能夠看懂。
  • 從0開始學Golang編程-環境安裝
    首先,在開始之前,我們需要安裝兩個東西:1:Golang https://golang.google.cn/dl/;2: Vs Code https://code.visualstudio.com/我們去Golang官網下載Goalng所需的運行環境,下載完成後,直接雙擊即可安裝完成後,在cmd命令行執行go version
  • Go語言(Golang)環境搭建詳解
    壓縮版的就是一個壓縮文件,可以解壓得到裡面的內容,他們的名字類似於:壓縮版我們下載後需要解壓,然後自己移動到要存放的路徑下,並且配置環境變量等信息,相比安裝版來說,比較複雜一些,手動配置的比較多。根據自己的作業系統選擇後,就可以下載開發工具包了,Go語言的官方下載地址是 https://golang.google.cn/dl/ 可以打開選擇版本下載。
  • 「Golang」for range 使用方法及避坑指南
    遍歷數組和切片遍歷數組和切片的方式都是一樣的,因為切片的使用概率要大於數組,所以主要講的切片的遍歷,數組可以與其相同方式進行使用,首先 Show me code!下面的代碼信息全部引用自:go/src/cmd/compile/internal/gc/range.go優化後代碼引自:https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-for-range/首先提前說一下下面會出現的所有變量名的含義,該含義全部引用自編譯器原始碼。
  • golang中Context的使用場景
    golang中Context的使用場景context在Go1.7之後就進入標準庫中了。它主要的用處如果用一句話來說,是在於控制goroutine的生命周期。當一個計算任務被goroutine承接了之後,由於某種原因(超時,或者強制退出)我們希望中止這個goroutine的計算任務,那麼就用得到這個Context了。
  • Golang語言情懷-第46期 Go 語言標準庫翻譯 compress/bzip2
    功能說明:.bz2文件的壓縮程序。   語  法:bzip2 [-cdfhkLstvVz][--repetitive-best][--repetitive-fast][- 壓縮等級][要壓縮的文件]   補充說明:bzip2採用新的壓縮演算法,壓縮效果比傳統的LZ77/LZ78壓縮演算法來得好。
  • Golang後臺單元測試實踐
    golang原生testing框架特點文件形式:文件以_test.go 結尾函數形式:func TestXxx(*testing.T)斷言:使用 t.Errorf 或相關方法來發出失敗信號運行:使用go test –v執行單元測試示例// 原函數 (in add.go)func