以下は、golangチュートリアル コラム Go 同時プログラミング用のミューテックスによって紹介されています。この記事が友人の役に立てば幸いです。必要!
注意事項: この記事は約 5 分 45 秒で読めます。欠点がある場合はさらにアドバイスをお願いします。読んでいただきありがとうございます。
同時アクセスの問題は、より一般的な大規模プロジェクトの設計で発生します。同時アクセスとは、データの正確性を解決し、同じクリティカル セクションのデータが 1 つのスレッドでのみ操作できるようにすることです。は日常生活で使用されますが、同時に実行されるシナリオも多数あります:
上記はすべて同時実行によって引き起こされるデータ精度の問題です。決定的な解決策は、今日の同時プログラミングで説明する Mutex 同時実行プリミティブである mutex lock を使用することです。 。
ミューテックスロック ミューテックスとは、同時実行競合を回避するために設けられた同時実行制御機構であり、「クリティカルセクション」という概念があります。
同時プログラミングのプロセスで、プログラム内の一部のリソースまたは変数が同時にアクセスまたは変更される場合、同時アクセスによって引き起こされるデータの不正確さを避けるために、プログラムのこの部分を次のようにする必要があります。最初に保護され、次に操作されます。操作が完了したら保護を解除します。保護されたプログラムのこの部分は、クリティカル セクションと呼ばれます。
ミューテックス ロックを使用して、クリティカル セクションが同時に 1 つのスレッドによってのみ保持されるように制限します。クリティカル セクションが現時点で 1 つのスレッドによって保持されている場合、他のスレッドがこれに入ろうとしている クリティカル セクションに到達すると、失敗するか、ロックが解放されるまで待機します。このクリティカル セクションを保持しているスレッドは終了し、他のスレッドはこのクリティカル セクションを取得する機会を得ます。
go mutex クリティカル セクションの図
Mutex は Go 言語で最も広く使用されている同期プリミティブであり、同時実行プリミティブとも呼ばれます。解決策目的は、共有リソースの読み取りと書き込みを同時に行い、データ競合の問題を回避することです。
Mutex には、Lock と Unlock の 2 つのメソッドが用意されています。クリティカル セクションに入るには、Lock メソッドを使用してロックし、クリティカル セクションを終了するには、Lock メソッドを使用します。セクションでは、Unlock メソッドを使用してロックを解放します。
type Locker interface { Lock() Unlock()}func(m *Mutex)Lock()func(m *Mutex)Unlock()
ゴルーチンが Lock メソッドを呼び出してロックを取得すると、現在ロックを取得しているゴルーチンがロックを解放するまで、他のゴルーチンは Lock 呼び出しをブロックします。
以下はカウンターの例です。カウンターを累積するために 100 個のゴルーチンによって実行され、最終的な出力結果は次のようになります:
package mainimport ( "fmt" "sync")func main() { var mu sync.Mutex countNum := 0 // 确认辅助变量是否都执行完成 var wg sync.WaitGroup // wg 添加数目要和 创建的协程数量保持一致 wg.Add(100) for i := 0; i < 100; i++ { go func() { defer wg.Done() for j := 0; j < 1000; j++ { mu.Lock() countNum++ mu.Unlock() } }() } wg.Wait() fmt.Printf("countNum: %d", countNum)}
多くの場合、Mutex は単独で使用されるのではなく、構造体の一部として Struct にネストされて使用されます。 埋め込まれた構造体に複数のフィールドがある場合、通常、制御するフィールドに Mutex を配置します。 . を入力し、スペースを使用してフィールドを区切ります。
ロックの取得、ロックの解放、1 ずつカウントするロジックをメソッドにカプセル化することもできます。
package mainimport ( "fmt" "sync")// 线程安全的计数器type Counter struct { CounterType int Name string mu sync.Mutex count uint64}// 加一方法func (c *Counter) Incr() { c.mu.Lock() defer c.mu.Unlock() c.count++}// 取数值方法 线程也需要受保护func (c *Counter) Count() uint64 { c.mu.Lock() defer c.mu.Unlock() return c.count}func main() { // 定义一个计数器 var counter Counter var wg sync.WaitGroup wg.Add(100) for i := 0; i < 100; i++ { go func() { defer wg.Done() for j := 0; j < 1000; j++ { counter.Incr() } }() } wg.Wait() fmt.Printf("%d\n", counter.Count())}
Q: Mutex が goroutine によってロックされている場合、待機中の他の goroutine は永久に待機することしかできないことはすでにご存知です。では、ロックが解放された後、待機中のゴルーチンのどれが最初に Mutex を取得するのでしょうか?
A: FIFO、先着順方式です。Go のゴルーチンのスケジューリングでは、ゴルーチンの実行を保証するためにキューが維持されます。ロックを取得したゴルーチンがクリティカル セクションの操作を完了すると、ロックすると、キュー内で最初にランク付けされたゴルーチンが、クリティカル セクションを操作するためのロックを取得します。
以上がGo 同時プログラミングの Mutex についての詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。