import "sync"

syncパッケージは、相互排他ロックなどの基本的な同期プリミティブを提供します。Once型以外は、ほぼ低レベルのライブラリルーチンから使用されることを前提にしています。高レベルの同期にはチャネルを使った通信が適しています。

パッケージファイル

mutex.go once.go rwmutex.go

Mutex型

Mutexは、相互排他ロックです。Mutexは他の構造体の一部分として作成することができます。Mutexのゼロ値は、アンロック状態のミューテックスです。

type Mutex struct {
    // contains unexported fields
}

(*Mutex) Lock関数

func (m *Mutex) Lock()

Lockは、mをロックします。すでにロックされていたときは、呼び出したゴルーチンはロックが可能になるまでブロックされます。

(*Mutex) Unlock関数

func (m *Mutex) Unlock()

Unlockは、mをアンロックします。mがロックされてないときにUnlockを呼び出すとランタイムエラーとなります。

ロックされたMutexは特定のゴルーチンとは関連付けられません。あるゴルーチンでMutexをロックし、そのあとでもう一方のゴルーチンでそれをアンロックするような取り決めは問題ありません。

Once型

Onceは、実行を確実に1回だけ行うオブジェクトです。

type Once struct {
    // contains unexported fields
}

func (*Once) Do

func (o *Once) Do(f func())

同じレシーバを使って、最初にDoを呼び出したときだけ、このDoは関数fを呼び出します。これを説明するために、まず宣言を行います。

var once Once

Do(f)が複数回呼び出されるとき、最初の呼び出しでのみ、fが実行されます。たとえ、fの値が変わっていても同じです。関数をそれぞれ実行させるためには、Onceの新しいインスタンスが必要です。

Doは、正確に一回だけ動作しなければならない初期化処理に使用します。関数fは引数を持たないので、Doの関数の実行に引数が必要であれば、次のように関数リテラルを使う必要があります。

config.once.Do(func() { config.init(filename) })

Doの呼び出しは、fから復帰するまで待たされるので、fに起因してDoが呼び出されてしまうケースでは、デッドロックが発生します。

RWMutex型

RWMutexは、Reader/Writerの相互排他ロックです。ロック状態を複数のReaderまたはひとつのWriterが持つことができます。RWMutexesは他の構造体の一部分として作成することができます。RWMutexのゼロ値は、アンロック状態のミューテックスです。

WriterはReaderより優先されるため、ブロックされたLock呼び出しが待機している間、RLocksが新たに許可されることはありません。

type RWMutex struct {
    // contains unexported fields
}

(*RWMutex) Lock関数

func (rw *RWMutex) Lock()

Lockは、rwの書き込みをロックします。すでに読み込みロックまたは書き込みロックされていれば、ロックが可能になるまでLockはブロックします。ブロックされたLock呼び出しは、確実にロックを得られるよう新しい読み込みロックを排他します。

(*RWMutex) RLock関数

func (rw *RWMutex) RLock()

RLockは、rwの読み込みをロックします。すでに書き込みロックされているか、または書き込みロックの解除待ちのwriterが存在するときは、このRLock呼び出しは、そのwriterがロックを解除するまでブロックします。

(*RWMutex) RUnlock関数

func (rw *RWMutex) RUnlock()

RUnlockは、RLockをひとつだけ解除するため同時にロックしている他のreaderには影響しません。rwが読み込みロックされていないときにRUnlockを呼び出すとランタイムエラーとなります。

(*RWMutex) Unlock関数

func (rw *RWMutex) Unlock()

Unlockは、書き込みをアンロックします。rwが書き込みロックされていないときにUnlockを呼び出すとランタイムエラーとなります。

Mutexと同じくロックされたRWMutexは特定のゴルーチンとは関連付けられません。あるゴルーチンでRWMutexをRLock (Lock)し、そのあとでもう一方のゴルーチンでそれをRUnlock (Unlock)するような取り決めは問題ありません。