golang のスピンロックの仕組みを教えて
Go言語でMutexを活用してスピンロックを実現できます.Mutexはsyncパッケージにて定義されており,Lock(), Unlock()の2つのメソッドを備えています.
スピンロックを利用した簡単なサンプルコードを示します。
package main
import (
"fmt"
"sync"
"sync/atomic"
)
type SpinLock struct {
flag int32
}
func (l *SpinLock) Lock() {
for !atomic.CompareAndSwapInt32(&l.flag, 0, 1) {
// 自旋等待
}
}
func (l *SpinLock) Unlock() {
atomic.StoreInt32(&l.flag, 0)
}
func main() {
var count int
var wg sync.WaitGroup
var lock SpinLock
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
lock.Lock()
defer lock.Unlock()
count++
}()
}
wg.Wait()
fmt.Println("Count:", count)
}
上の例では、SpinLock構造体を定義しており、そこでflagフィールドはロックの状態を示すために使われます。Lock()メソッドは原子操作atomic.CompareAndSwapInt32を使用してロックを取得しようと試み、もし成功すると実行を続けますが、さもなければ自転待ちを続けます。Unlock()メソッドはatomic.StoreInt32を使用してロックを解放します。
メイン関数では1000個のgoroutineが作られ、それぞれがロックをかけてアトミックにcountを操作し、最後にcountの値を出力する。スピンロックの使用によりcountの操作はスレッドセーフに保証されている。
スピンロックはロック時間が短く競合の激しい場面で有効ですが、ロック時間が長い、または競合が激しい場合にはパフォーマンスを低下させてしまうおそれがあります。そのため、実際の開発では、状況に応じて適切なロック機構を選択することが重要です。