Golang同期:ロックの使用例の詳細


反発ロック
反発ロックは、従来のコンカレント・プログラムが共有リソースにアクセス制御する主な手段である.標準ライブラリパッケージsyncのMutex構造体タイプによって表されます.2つの公開方法しかありません
  • Lock
  • Unlock

  • タイプsync.Mutexのゼロ値は、ロックされていない反発量を表す.
    var mutex sync.Mutex
    mutex.Lock()

    // test for Go
    //
    // Copyright (c) 2015 - Batu <[email protected]>
    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    func main(){
        //  
        var mutex sync.Mutex
        fmt.Println("Lock the lock. (G0)")
        //  mutex
        mutex.Lock()
    
        fmt.Println("The lock is locked.(G0)")
        for i := 1; i < 4; i++ {
            go func(i int) {
                fmt.Printf("Lock the lock. (G%d)
    "
    , i) mutex.Lock() fmt.Printf("The lock is locked. (G%d)
    "
    , i) }(i) } // , time.Sleep(time.Second) fmt.Println("Unlock the lock. (G0)") // mutex mutex.Unlock() fmt.Println("The lock is unlocked. (G0)") // , time.Sleep(time.Second) }

    印刷結果:
    /usr/local/go/bin/go run/Users/liuxinming/go/src/example/test/test.go Lock the lock. (G0) The lock is locked.(G0) Lock the lock. (G1) Lock the lock. (G2) Lock the lock. (G3) Unlock the lock. (G0) The lock is unlocked. (G0) The lock is locked. (G1)
    推奨:同じ反発ロックのペアロックとロック解除操作は、同じ階層のコードブロックに配置されます.
    リードライトロック
    読み書き操作に対する反発ロックは、それぞれ読み書き操作に対してロックおよびロック解除操作を行うことができる.読み書きロックに従うアクセス制御規則は、反発ロックとは異なります.
  • 任意の読み取り動作を同時に行うことができる
  • 同じ時刻に、
  • の書き込みのみが許可する.
    =============華やかな分割線========
  • かつ1つの書き込み動作が実行する間、読み出し動作の実行も許可されない
  • .
  • 読み書きロック制御下の複数の書き込み動作の間は、反発する
  • である.
  • 書き込み操作と読み出し操作の間も反発する
  • である.
  • 複数の読み出し動作の間には反発関係が存在しない
  • 読み書きロックは、構造体タイプsyncによって構成する.RWMutex代表
    書き込み操作のロックとロック解除*func(*RWMutex)Lock*func(*RWMutex)Unlock読み込み操作のロックとロック解除*func(*RWMutex)Rlock*func(*RWMutex)RUnlock
    注意:+書き込みロック解除を行うと、読み取りロックをしようとしてブロックされているGoroutineをすべて呼び覚まそうとします.+読み取りロックは、進行中に何の読み取りロックもない状態で書き込みロックをしようとしてブロックされたGoroutine+書き込みロックされていない読み書きロックを書き込みロックしようとすると、実行時のパニック+を引き起こし、読み取りロックされていない読み書きロックを読み取りロックすることはできません.
    ロックの完全な例
    // test for Go
    //
    // Copyright (c) 2015 - Batu <[email protected]>
    //
    //           ,     ,      Goroutine                .
    //                         ,            ,               ,                    
    //                            .            ,        .
    //   :             1,             2,              3,    
    //                 ,    .       ,         .
    package main
    
    import (
        "fmt"
        "sync"
        "time"
        "os"
        "errors"
        "io"
    )
    
    //         
    type DataFile interface {
        //        
        Read() (rsn int64, d Data, err error)
        //        
        Write(d Data) (wsn int64, err error)
        //               
        Rsn() int64
        //               
        Wsn() int64
        //         
        DataLen() uint32
    }
    
    //    
    type Data []byte
    
    //         
    type myDataFile struct {
        f *os.File  //  
        fmutex sync.RWMutex //         
        woffset int64 //            
        roffset int64 //            
        wmutex sync.Mutex //            
        rmutex sync.Mutex //            
        dataLen uint32 //     
    }
    
    //   DataFile      ,    DataFile    
    func NewDataFile(path string, dataLen uint32) (DataFile, error){
        f, err := os.OpenFile(path, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0666)
        //f,err := os.Create(path)
        if err != nil {
            fmt.Println("Fail to find", f, "cServer start Failed")
            return nil, err
        }
    
        if dataLen == 0 {
            return nil, errors.New("Invalid data length!")
        }
    
        df := &myDataFile{
            f : f,
            dataLen:dataLen,
        }
    
        return df, nil
    }
    
    //         ,                ,          Data             
    
    func (df *myDataFile) Read() (rsn int64, d Data, err error){
        //          
        var offset int64
        //      
        df.rmutex.Lock()
        offset = df.roffset
        //      ,      +     
        df.roffset += int64(df.dataLen)
        //      
        df.rmutex.Unlock()
    
        //       ,           
        rsn = offset / int64(df.dataLen)
        bytes := make([]byte, df.dataLen)
        for {
            //   :   
            df.fmutex.RLock()
            _, err = df.f.ReadAt(bytes, offset)
            if err != nil {
                //        Goroutine       Goroutine ,           roffset          woffset  
                //     ,              ,      df.f.ReadAt                nil   io.EOF    
                //       EOF         
                // so          ,EOF      ,     ,          ,        .
                if err == io.EOF {
                    //  ,    for        ,      fmutex       ,                .
                    //    Goroutine       .        .
                    // so    return & continue                      
                    df.fmutex.RUnlock()
                    //  ,  EOF          ,      ,     
                    //                .
                    continue
                }
            }
            break
        }
        d = bytes
        df.fmutex.RUnlock()
        return
    }
    
    func (df *myDataFile) Write(d Data) (wsn int64, err error){
        //          
        var offset int64
        df.wmutex.Lock()
        offset = df.woffset
        df.woffset += int64(df.dataLen)
        df.wmutex.Unlock()
    
        //       ,          
        wsn = offset / int64(df.dataLen)
        var bytes []byte
        if len(d) > int(df.dataLen){
            bytes = d[0:df.dataLen]
        }else{
            bytes = d
        }
        df.fmutex.Lock()
        df.fmutex.Unlock()
        _, err = df.f.Write(bytes)
    
        return
    }
    
    func (df *myDataFile) Rsn() int64{
        df.rmutex.Lock()
        defer df.rmutex.Unlock()
        return df.roffset / int64(df.dataLen)
    }
    
    func (df *myDataFile) Wsn() int64{
        df.wmutex.Lock()
        defer df.wmutex.Unlock()
        return df.woffset / int64(df.dataLen)
    }
    
    func (df *myDataFile) DataLen() uint32 {
        return df.dataLen
    }
    
    func main(){
        //       
        var dataFile DataFile
        dataFile,_ = NewDataFile("./mutex_2015_1.dat", 10)
    
        var d=map[int]Data{
            1:[]byte("batu_test1"),
            2:[]byte("batu_test2"),
            3:[]byte("test1_batu"),
        }
    
        //    
        for i:= 1; i < 4; i++ {
            go func(i int){
                wsn,_ := dataFile.Write(d[i])
                fmt.Println("write i=", i,",wsn=",wsn, ",success.")
            }(i)
        }
    
        //    
        for i:= 1; i < 4; i++ {
            go func(i int){
                rsn,d,_ := dataFile.Read()
                fmt.Println("Read i=", i,",rsn=",rsn,",data=",d, ",success.")
            }(i)
        }
    
        time.Sleep(10 * time.Second)
    }

    印刷結果:
    /usr/local/go/bin/go run/Users/liuxinming/go/src/example/test/test.go write i= 3 ,wsn= 1 ,success. write i= 1 ,wsn= 0 ,success. Read i= 1 ,rsn= 1 ,data= [116 101 115 116 49 95 98 97 116 117] ,success. write i= 2 ,wsn= 2 ,success. Read i= 2 ,rsn= 0 ,data= [98 97 116 117 95 116 101 115 116 49] ,success. Read i= 3 ,rsn= 2 ,data= [98 97 116 117 95 116 101 115 116 50] ,success.