golang読み書きロックはスレッドの安全を保証する

8885 ワード

いつ鍵を使う必要がありますか?


反発ロック


反発ロックは共有リソースへのアクセスを制御する一般的な方法であり、同時に1つの反発ロックだけが共有リソースへのアクセスを制御する一般的な方法であることを保証し、同時に1つのgoroutineだけが共有リソースにアクセスできることを保証することができる(同じ時点で1つのスレッドだけがロックを取得できる)
まず、マルチスレッドがグローバル変数に同時にアクセスした場合、結果はどうなるかを、同時読み書きの例で示します.
package main
import ("fmt")
 
var count int
 
func main() {
    for i := 0; i < 2; i++ {
        go func() {
            for i := 1000000; i > 0; i-- {
                count ++
            }
            fmt.Println(count)
        }()
    }
 
    fmt.Scanf("
"
) // }980117 1011352 // :200000

コードを修正し、累積した場所に反発ロックを追加すると、毎回得られる結果が所望の値であることが保証されます.
package main
import ("fmt"
    "sync"
)

var (
    count int
    lock sync.Mutex
)

func main() {
    for i := 0; i < 2; i++ {
        go func() {
            for i := 1000000; i > 0; i-- {
                lock.Lock()
                count ++
                lock.Unlock()
            }
            fmt.Println(count)
        }()
    }

    fmt.Scanf("
"
) // }1952533 2000000 //

読み書きロック(sync.RWMutex)


読み書きが少ない環境では、反発ロックよりも効率的に読み書き反発ロック(sync.RWMutex)を優先的に使用できます.syncパッケージのRWMutexは、読み書き反発ロックのパッケージを提供します.
リード・ライト・ロックには、リード・ロックとライト・ロックがあります.
  • 書き込みロックが設定されている場合、他の読み取りスレッドおよび書き込みスレッドはロックを取得できません.この場合、反発ロックの機能と同じ
  • リードロックが設定されている場合、他の書き込みスレッドはロックを取得できないが、他の読み取りスレッドはロック
  • を取得することができる.
    書き込みロックを設定することで、データの一貫性を実現できます.
    package main
    import ("fmt"
        "sync"
    )
     
    var (
        count int
        rwLock sync.RWMutex
    )
     
    func main() {
        for i := 0; i < 2; i++ {
            go func() {
                for i := 1000000; i > 0; i-- {
                    rwLock.Lock()
                    count ++
                    rwLock.Unlock()
                }
                fmt.Println(count)
            }()
        }
     
        fmt.Scanf("
    "
    ) // }1968637 2000000