雖然提供了channel來保證協程中的通訊,在某些情況下,還是更適合使用鎖來保證執行緒的安全.
go語言中的鎖分兩種:互斥鎖mutex和讀寫鎖rwmutex
1.互斥鎖 mutex
互斥鎖是執行緒安全中最常用的鎖,基本原理就是對某個操作進行加鎖,無論讀寫同一時間內只有乙個協程可以對當前資料進行操作,只有對當前鎖解鎖後其他協程才可以繼續進行操作,互斥鎖不可以重入,對乙個已經加過鎖的資料再次加鎖會引起恐慌,同樣的對乙個未加鎖的操作進行解鎖也會引發恐慌.
2.讀寫鎖rwmutex
互斥鎖可以保證執行緒安全,但是相應的,互斥鎖由於強制性的序列操作,會導致效能有一定下降,為了提高加鎖效能,go語言也提供了高效能鎖讀寫鎖.對資料的操作主要是讀寫互斥,因為對資料加鎖的主要原因是需要對資料進行修改,若不加鎖可能會導致讀取到的資料不同,而對於讀多,寫少的場景來說,在資料不需要寫的時候可以任意讀,因為資料不會發生改變, 所以此時不會有執行緒安全問題,所以讀寫鎖的讀鎖可以重入,在已經有讀鎖的情況下可以重複加任意多的讀鎖,讀鎖和寫鎖互斥,在讀鎖未全部解鎖的情況下,寫鎖操作會阻塞,直到所有讀鎖都解鎖才會加寫鎖,在寫鎖定的情況下,其他協程的讀和寫都是被禁止的, 寫鎖無法重入,直到寫鎖解鎖,其他讀寫操作才可以繼續進行
原始碼解析:
以上**為讀鎖的原始碼,可以看到其中第6行,若當前有寫鎖定,則等待,即在寫鎖定時無法進行讀加鎖,讀加鎖協程會阻塞func (rw *rwmutex) rlock()
if atomic.addint32(&rw.readercount, 1) < 0
if race.enabled
}
以上**為寫鎖的原始碼,寫鎖首先是解決與其他寫鎖的衝突,在其他寫鎖定解鎖的情況下才可以繼續執行寫鎖定,同樣的,在有讀鎖定的情況下也無法進行寫鎖定,在第11行可以看到,需要等待所有讀鎖都解鎖的情況下才可以繼續寫鎖定,負責寫鎖定協程會阻塞.func (rw *rwmutex) lock()
// first, resolve competition with other writers.
rw.w.lock()
// announce to readers there is a pending writer.
r := atomic.addint32(&rw.readercount, -rwmutexmaxreaders) + rwmutexmaxreaders
// wait for active readers.
if r != 0 && atomic.addint32(&rw.readerwait, r) != 0
if race.enabled
}
由**可以看出,寫鎖定和讀鎖定互斥,讀鎖定和讀鎖定不互斥,寫鎖定和寫鎖定互斥.
Go語言中的普通鎖Mutex和讀寫鎖RWMutex
type mutex struct 案例1.用普通鎖來實現火車站賣票 mymutexdes project main.go package main import fmt sync time 全域性變數 var ticks 100 var wg sync.waitgroup var mutex sy...
go 語言中的繼承
go 語言中可以通過匿名field來實現繼承的效果,type t1 struct func t t1 log func t t1 print type t2 struct t2 t2 可以通過t2.log 直接訪問t1的method,就像物件導向的繼承之後一樣訪問,不過這裡要注意的傳遞到log的是t...
Go語言中的常量
常量,一經定義不可更改的量。功能角度看,當出現不需要被更改的資料時,應該使用常量進行儲存,例如圓周率。從語法的角度看,使用常量可以保證資料,在整個執行期間內,不會被更改。例如當預處理器的架構型別,可以保證不被更改。語法如下 const 常量名 可選的型別 常量值 const c1 int 1000g...