1. 程式人生 > >Go併發程式設計--基於channel訊號量來實現互斥鎖

Go併發程式設計--基於channel訊號量來實現互斥鎖

概述

根據前面的一片文章:《Go併發程式設計–通過channel來實現訊號量原語》我們實現了訊號量的基本原語P和V操作,本章介紹如何通過P操作和V操作來實現互斥鎖。

實現原理

當我們把channel的容量設定為1時,P和V操作就變成了,lock和unlock操作。為什麼呢?我們來看下程式碼實現:

/* mutexes */
func (s semaphore) Lock() {
    s.P(1)
}

func (s semaphore) Unlock() {
    s.V(1)
}

上篇講過P和V操作的實現,當channel的容量只有一個,此時P和V的數量變為1時,進行P操作的協程只能有一個,在該協程執行完P操作沒有執行V操作時,其他協程只能等待,這樣就實現了只能有一個協程訪問臨界區的功能。

完整程式碼

package main

import (
    "fmt"
    "os"
    "time"
)

type Empty interface {}
type semaphore chan Empty

// 實現訊號量原語
// acquire n resources
func (s semaphore) P(n int) {
    e := new(Empty)
    for i := 0; i < n; i++ {
        s <- e
    }
}

// release n resources
func (s semaphore) V(n int
) { for i := 0; i < n; i++ { <-s } } // 通過以上原語實現互斥鎖 /* mutexes */ func (s semaphore) Lock() { s.P(1) } func (s semaphore) Unlock() { s.V(1) } // 工作協程,這裡只是列印0-99的整數 func printInt(sem semaphore) { sem.Lock() for i := 0; i < 100; i++ { fmt.Fprintf(os.Stderr, "%d\n"
, i) } sem.Unlock() } func main() { sem := make(semaphore, 1) go printInt(sem) go printInt(sem) // 等待兩個goroutine結束 time.Sleep(10e9) fmt.Fprintf(os.Stderr, "end\n") }

當channel容量時1是,就只能有一個協程能完成P操作,直到該協程完成了V操作,其他協程才能進行P操作,這樣就實現了互斥鎖。

總結

通過channel實現的訊號量原語,我們實現了互斥鎖。通過P和V原語我們還能實現訊號量的一些操作,從而更好的控制協程間的通訊。如何實現訊號量操作,請繼續看後面的文章。