Golang同期:ロックの使用例の詳細
反発ロック
反発ロックは、従来のコンカレント・プログラムが共有リソースにアクセス制御する主な手段である.標準ライブラリパッケージsyncのMutex構造体タイプによって表されます.2つの公開方法しかありません Lock Unlock
タイプsync.Mutexのゼロ値は、ロックされていない反発量を表す.
例
印刷結果:
/usr/local/go/bin/go run/Users/liuxinming/go/src/example/test/test.go Lock the lock. (G0) The lock is locked.(G0) Lock the lock. (G1) Lock the lock. (G2) Lock the lock. (G3) Unlock the lock. (G0) The lock is unlocked. (G0) The lock is locked. (G1)
推奨:同じ反発ロックのペアロックとロック解除操作は、同じ階層のコードブロックに配置されます.
リードライトロック
読み書き操作に対する反発ロックは、それぞれ読み書き操作に対してロックおよびロック解除操作を行うことができる.読み書きロックに従うアクセス制御規則は、反発ロックとは異なります.任意の読み取り動作を同時に行うことができる 同じ時刻に、 の書き込みのみが許可する.
=============華やかな分割線========かつ1つの書き込み動作が実行する間、読み出し動作の実行も許可されない .読み書きロック制御下の複数の書き込み動作の間は、反発する である.書き込み操作と読み出し操作の間も反発する である.複数の読み出し動作の間には反発関係が存在しない 読み書きロックは、構造体タイプsyncによって構成する.RWMutex代表
書き込み操作のロックとロック解除*func(*RWMutex)Lock*func(*RWMutex)Unlock読み込み操作のロックとロック解除*func(*RWMutex)Rlock*func(*RWMutex)RUnlock
注意:+書き込みロック解除を行うと、読み取りロックをしようとしてブロックされているGoroutineをすべて呼び覚まそうとします.+読み取りロックは、進行中に何の読み取りロックもない状態で書き込みロックをしようとしてブロックされたGoroutine+書き込みロックされていない読み書きロックを書き込みロックしようとすると、実行時のパニック+を引き起こし、読み取りロックされていない読み書きロックを読み取りロックすることはできません.
ロックの完全な例
印刷結果:
/usr/local/go/bin/go run/Users/liuxinming/go/src/example/test/test.go write i= 3 ,wsn= 1 ,success. write i= 1 ,wsn= 0 ,success. Read i= 1 ,rsn= 1 ,data= [116 101 115 116 49 95 98 97 116 117] ,success. write i= 2 ,wsn= 2 ,success. Read i= 2 ,rsn= 0 ,data= [98 97 116 117 95 116 101 115 116 49] ,success. Read i= 3 ,rsn= 2 ,data= [98 97 116 117 95 116 101 115 116 50] ,success.
反発ロックは、従来のコンカレント・プログラムが共有リソースにアクセス制御する主な手段である.標準ライブラリパッケージsyncのMutex構造体タイプによって表されます.2つの公開方法しかありません
タイプsync.Mutexのゼロ値は、ロックされていない反発量を表す.
var mutex sync.Mutex
mutex.Lock()
例
// test for Go
//
// Copyright (c) 2015 - Batu <[email protected]>
package main
import (
"fmt"
"sync"
"time"
)
func main(){
//
var mutex sync.Mutex
fmt.Println("Lock the lock. (G0)")
// mutex
mutex.Lock()
fmt.Println("The lock is locked.(G0)")
for i := 1; i < 4; i++ {
go func(i int) {
fmt.Printf("Lock the lock. (G%d)
", i)
mutex.Lock()
fmt.Printf("The lock is locked. (G%d)
", i)
}(i)
}
// ,
time.Sleep(time.Second)
fmt.Println("Unlock the lock. (G0)")
// mutex
mutex.Unlock()
fmt.Println("The lock is unlocked. (G0)")
// ,
time.Sleep(time.Second)
}
印刷結果:
/usr/local/go/bin/go run/Users/liuxinming/go/src/example/test/test.go Lock the lock. (G0) The lock is locked.(G0) Lock the lock. (G1) Lock the lock. (G2) Lock the lock. (G3) Unlock the lock. (G0) The lock is unlocked. (G0) The lock is locked. (G1)
推奨:同じ反発ロックのペアロックとロック解除操作は、同じ階層のコードブロックに配置されます.
リードライトロック
読み書き操作に対する反発ロックは、それぞれ読み書き操作に対してロックおよびロック解除操作を行うことができる.読み書きロックに従うアクセス制御規則は、反発ロックとは異なります.
=============華やかな分割線========
書き込み操作のロックとロック解除*func(*RWMutex)Lock*func(*RWMutex)Unlock読み込み操作のロックとロック解除*func(*RWMutex)Rlock*func(*RWMutex)RUnlock
注意:+書き込みロック解除を行うと、読み取りロックをしようとしてブロックされているGoroutineをすべて呼び覚まそうとします.+読み取りロックは、進行中に何の読み取りロックもない状態で書き込みロックをしようとしてブロックされたGoroutine+書き込みロックされていない読み書きロックを書き込みロックしようとすると、実行時のパニック+を引き起こし、読み取りロックされていない読み書きロックを読み取りロックすることはできません.
ロックの完全な例
// test for Go
//
// Copyright (c) 2015 - Batu <[email protected]>
//
// , , Goroutine .
// , , ,
// . , .
// : 1, 2, 3,
// , . , .
package main
import (
"fmt"
"sync"
"time"
"os"
"errors"
"io"
)
//
type DataFile interface {
//
Read() (rsn int64, d Data, err error)
//
Write(d Data) (wsn int64, err error)
//
Rsn() int64
//
Wsn() int64
//
DataLen() uint32
}
//
type Data []byte
//
type myDataFile struct {
f *os.File //
fmutex sync.RWMutex //
woffset int64 //
roffset int64 //
wmutex sync.Mutex //
rmutex sync.Mutex //
dataLen uint32 //
}
// DataFile , DataFile
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,
}
return df, nil
}
// , , Data
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)
for {
// :
df.fmutex.RLock()
_, err = df.f.ReadAt(bytes, offset)
if err != nil {
// Goroutine Goroutine , roffset woffset
// , , df.f.ReadAt nil io.EOF
// EOF
// so ,EOF , , , .
if err == io.EOF {
// , for , fmutex , .
// Goroutine . .
// so return & continue
df.fmutex.RUnlock()
// , EOF , ,
// .
continue
}
}
break
}
d = bytes
df.fmutex.RUnlock()
return
}
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()
df.fmutex.Unlock()
_, err = df.f.Write(bytes)
return
}
func (df *myDataFile) Rsn() int64{
df.rmutex.Lock()
defer df.rmutex.Unlock()
return df.roffset / int64(df.dataLen)
}
func (df *myDataFile) Wsn() int64{
df.wmutex.Lock()
defer df.wmutex.Unlock()
return df.woffset / int64(df.dataLen)
}
func (df *myDataFile) DataLen() uint32 {
return df.dataLen
}
func main(){
//
var dataFile DataFile
dataFile,_ = NewDataFile("./mutex_2015_1.dat", 10)
var d=map[int]Data{
1:[]byte("batu_test1"),
2:[]byte("batu_test2"),
3:[]byte("test1_batu"),
}
//
for i:= 1; i < 4; i++ {
go func(i int){
wsn,_ := dataFile.Write(d[i])
fmt.Println("write i=", i,",wsn=",wsn, ",success.")
}(i)
}
//
for i:= 1; i < 4; i++ {
go func(i int){
rsn,d,_ := dataFile.Read()
fmt.Println("Read i=", i,",rsn=",rsn,",data=",d, ",success.")
}(i)
}
time.Sleep(10 * time.Second)
}
印刷結果:
/usr/local/go/bin/go run/Users/liuxinming/go/src/example/test/test.go write i= 3 ,wsn= 1 ,success. write i= 1 ,wsn= 0 ,success. Read i= 1 ,rsn= 1 ,data= [116 101 115 116 49 95 98 97 116 117] ,success. write i= 2 ,wsn= 2 ,success. Read i= 2 ,rsn= 0 ,data= [98 97 116 117 95 116 101 115 116 49] ,success. Read i= 3 ,rsn= 2 ,data= [98 97 116 117 95 116 101 115 116 50] ,success.