Golang同期:条件変数とロックを組み合わせて使用
条件変数の役割は、同じ時点で1つのスレッドのみが1つの共有データにアクセスすることを保証するのではなく、対応する共有データの状態が変化したときに、それによってブロックされた他のスレッドに通知することである.条件変数と反発量を組み合わせて を用いる.反発量共有データへのアクセスに反発サポート を提供する.条件変数は、状態の変化について関連スレッドに通知する .
3つの操作方法通知待ち:wait は現在のスレッドをブロックし、この条件変数からの通知 が受信されるまでブロックする.
単発通知:signal は、共有データの状態が変化したことを示す通知を、その通知を待っている少なくとも1つのスレッドに条件変数を送信させる.
ブロードキャスト通知:broadcast は、その通知を待っているすべてのスレッドに条件変数を通知する.
宣言
func NewCond(l Locker) *Cond
例
前節のロック使用コードの変更
Golang同期:ロックの使用例詳細転送ゲート:http://blog.csdn.net/liuxinmingcode/article/details/50044327
Read()メソッドの改造は以下の通りです.
Write()メソッドの改造は以下の通りです.
1つのデータブロックに1つの読み取り操作しかないため、条件変数Signalメソッドを使用して、このために待機しているWaitメソッドを通知し、関連するGoroutineを起動します.
もう一つ忘れてはいけないことがあります.rcondフィールドを初期化します.
ソース:https://github.com/lxmgo/learngo
3つの操作方法
宣言
func NewCond(l Locker) *Cond
例
前節のロック使用コードの変更
Golang同期:ロックの使用例詳細転送ゲート:http://blog.csdn.net/liuxinmingcode/article/details/50044327
Read()メソッドの改造は以下の通りです.
func (df *myDataFile) Read() (rsn int64, d Data, err error){
//
var offset int64
//
df.rmutex.Lock()
offset = df.roffset
// , +
df.roffset += int64(df.dataLen)
//
df.rmutex.Unlock()
// ,
rsn = offset / int64(df.dataLen)
bytes := make([]byte, df.dataLen)
// :
df.fmutex.RLock()
defer df.fmutex.RUnlock()
for {
_, err = df.f.ReadAt(bytes, offset)
if err != nil {
if err == io.EOF {
// fmutex ,
df.rcond.Wait()
continue
}
}
return
}
d = bytes
return
}
Write()メソッドの改造は以下の通りです.
func (df *myDataFile) Write(d Data) (wsn int64, err error){
//
var offset int64
df.wmutex.Lock()
offset = df.woffset
df.woffset += int64(df.dataLen)
df.wmutex.Unlock()
// ,
wsn = offset / int64(df.dataLen)
var bytes []byte
if len(d) > int(df.dataLen){
bytes = d[0:df.dataLen]
}else{
bytes = d
}
df.fmutex.Lock()
defer df.fmutex.Unlock()
_, err = df.f.Write(bytes)
//
df.rcond.Signal()
return
}
1つのデータブロックに1つの読み取り操作しかないため、条件変数Signalメソッドを使用して、このために待機しているWaitメソッドを通知し、関連するGoroutineを起動します.
もう一つ忘れてはいけないことがあります.rcondフィールドを初期化します.
func NewDataFile(path string, dataLen uint32) (DataFile, error){
//f, err := os.OpenFile(path, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0666)
f,err := os.Create(path)
if err != nil {
fmt.Println("Fail to find", f, "cServer start Failed")
return nil, err
}
if dataLen == 0 {
return nil, errors.New("Invalid data length!")
}
df := &myDataFile{
f : f,
dataLen:dataLen,
}
// ( ), *sync.Cond , Wait,Signal,Broadcast
df.rcond = sync.NewCond(df.fmutex.RLocker())
return df, nil
}
ソース:https://github.com/lxmgo/learngo