<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ### 使用互斥鎖線程同步 互斥鎖是最簡單的一種鎖類型,同時也比較暴力,當一個goroutine獲得了鎖之后,其他goroutine就只能乖乖等到這個goroutine釋放該鎖。go語言使用sync.Mutex實現互斥鎖。 Mutex 是最簡單的一種鎖類型,同時也比較暴力,當一個 goroutine 獲得了 Mutex 后,其他 goroutine 就只能乖乖等到這個 goroutine 釋放該 Mutex。 參考:http://c.biancheng.net/view/107.html 參考:https://blog.csdn.net/luoye4321/article/details/82433144 ``` package main import ( "fmt" "sync" ) var ( // 邏輯中使用的某個變量 count int // 與變量對應的使用互斥鎖 countGuard sync.Mutex ) func GetCount() int { // 鎖定 countGuard.Lock() // 在函數退出時解除鎖定 defer countGuard.Unlock() return count } func SetCount(c int) { countGuard.Lock() count = c countGuard.Unlock() } func main() { // 可以進行并發安全的設置 SetCount(1) // 可以進行并發安全的獲取 fmt.Println(GetCount()) } ``` ``` package main import ( "fmt" "sync" "time" ) type MutexInfo struct { mutex sync.Mutex infos []int } func (m *MutexInfo) addInfo(value int) { m.mutex.Lock() m.infos = append(m.infos, value) m.mutex.Unlock() } func main() { m := MutexInfo{} for i := 0; i < 10; i++ { go m.addInfo(i) } time.Sleep(time.Second * 5) fmt.Println(m.infos) // [0 1 2 5 3 6 7 8 9 4] } ``` 我們通過多次運行發現,輸出的結果并不總是從0到9按順序輸出,說明創建的10個goroutine并不是有序的搶占線程的執行權,也就是說這種同步并不是有序的同步,我們可以讓10個goroutine一個一個的同步執行,但是并不能安排執行次序。 運行到這里,假如我們注釋掉同步鎖的代碼為發生什么? 我們將addInfo方法修改如下: ``` func (m *MutexInfo) addInfo(value int) { //m.mutex.Lock() m.infos = append(m.infos, value) //m.mutex.Unlock() } ``` 運行代碼,輸出:[1 0 2] 結果是不是出乎意料?為什么寫了10個輸入,只有3個值輸入成功?這時候我們不得不解釋線程的另一個概念,那就是線程安全。 我們先看下go語言中slice的append過程,使用append添加一個元素時,可能會有兩步來完成:先獲取當前切片數組的容量,比如當前容量是2,然后在新的存儲區開辟一塊新的存儲單元,容量為2+1,并將原來的值和新的值存入新的存儲單元。在沒有同步鎖的情況下,如果兩個線程同時執行添加元素的操作,這時候可能只有一個被寫入成功。這種情況就是非線程安全,相比之下,如果同時對一個int類型數據進行操作,就不會出現這種非線程安全的情況。 ### 線程同步(讀寫互斥鎖) go語言提供了另一種更加友好的線程同步的方式:sync.RWMutex。相對于互斥鎖的簡單暴力,讀寫鎖更加人性化,是經典的單寫多讀模式。在讀鎖占用的情況下,會阻止寫,但不阻止讀,也就是多個goroutine可同時獲取讀鎖,而寫鎖會阻止其他線程的讀寫操作。 RWMutex 相對友好些,是經典的單寫多讀模型。在讀鎖占用的情況下,會阻止寫,但不阻止讀,也就是多個 goroutine 可同時獲取讀鎖(調用 RLock() 方法;而寫鎖(調用 Lock() 方法)會阻止任何其他 goroutine(無論讀和寫)進來,整個鎖相當于由該 goroutine 獨占。從 RWMutex 的實現看,RWMutex 類型其實組合了 Mutex ``` type RWMutex struct { ? ? w Mutex ? ? writerSem uint32 ? ? readerSem uint32 ? ? readerCount int32 ? ? readerWait int32 } ``` ``` package main import ( "fmt" "sync" "time" ) // 創建一個結構體 type MutexInfo struct { mutex sync.Mutex infos []int } //執行讀的函數 func (m *MutexInfo) addInfo(value int) { // 加鎖 m.mutex.Lock() // 結束時 釋放鎖 去鎖操作 defer m.mutex.Unlock() fmt.Println("開始讀", value) fmt.Println("結束讀", value) } // 執行寫的函數 func (m *MutexInfo) readInfo(value int) { // 加鎖 m.mutex.Lock() // 釋放 defer m.mutex.Unlock() fmt.Println("開始寫", value) m.infos = append(m.infos, value) fmt.Println("結束寫", value) } func main() { //實例化結構體 m := MutexInfo{} // 創建10個線程 for i := 0; i < 10; i++ { go m.addInfo(i) go m.readInfo(i) } time.Sleep(time.Second * 5) // 輸出 結構體接收數據 infos fmt.Println(m.infos) } ``` 開始讀 1 結束讀 1 ... 結束讀 8 開始讀 9 結束讀 9 [0 7 1 2 3 4 5 6 8 9] 從結果我們可以看出,開始的時候讀線程占用讀鎖,并且多個線程可以同時開始讀操作,但是寫操作只能單個進行。 ### 使用條件變量實現線程同步 go語言提供了條件變量sync.Cond,sync.Cond方法如下: Wait,Signal,Broadcast。 Wait添加一個計數,也就是添加一個阻塞的goroutine。 Signal解除一個goroutine的阻塞,計數減一。 Broadcast接觸所有wait goroutine的阻塞。 ``` package main import ( "fmt" "sync" "time" ) func printIntValue(value int, cond *sync.Cond) { cond.L.Lock() if value < 5 { //value小于5時,進入等待狀態 cond.Wait() } //大于5的正常輸出 fmt.Println(value) cond.L.Unlock() } func main() { //條件等待 mutex := sync.Mutex{} //使用鎖創建一個條件等待 cond := sync.NewCond(&mutex) for i := 0; i < 10; i++ { go printIntValue(i, cond) } time.Sleep(time.Second * 1) cond.Signal() //解除一個阻塞 time.Sleep(time.Second * 1) cond.Broadcast() //解除全部阻塞 time.Sleep(time.Second * 1) } ``` 運行后先輸出滿足條件的值:5 6 7 8 9 解除一個阻塞,輸出0,解除全部阻塞,輸出1 2 3 4 go語言多線程支持全局唯一性操作,即一個只允許goruntine調用一次,重復調用無效。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看