ホームページ  >  記事  >  バックエンド開発  >  Go 同時プログラミングの Mutex について

Go 同時プログラミングの Mutex について

藏色散人
藏色散人転載
2020-11-16 13:53:522617ブラウズ

以下は、golangチュートリアル コラム Go 同時プログラミング用のミューテックスによって紹介されています。この記事が友人の役に立てば幸いです。必要!

注意事項: この記事は約 5 分 45 秒で読めます。欠点がある場合はさらにアドバイスをお願いします。読んでいただきありがとうございます。

同時アクセスの問題は、より一般的な大規模プロジェクトの設計で発生します。同時アクセスとは、データの正確性を解決し、同じクリティカル セクションのデータが 1 つのスレッドでのみ操作できるようにすることです。は日常生活で使用されますが、同時に実行されるシナリオも多数あります:

  • Counter: カウンタの結果は不正確です;
  • Second Kill System : 同時に多数のアクセスがあったため売られ過ぎ;
  • ユーザー アカウントの異常: 同時支払いによるアカウントの貸越;
  • バッファデータ異常: バッファ更新によるデータが乱れています。

上記はすべて同時実行によって引き起こされるデータ精度の問題です。決定的な解決策は、今日の同時プログラミングで説明する 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)}

Actual use

多くの場合、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 サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。