> 條件變量的作用并不是保證在同一時刻僅有一個線程訪問某一個共享數據,而是在對應的共享數據的狀態發生變化時,通知其他因此而被阻塞的線程。
- 條件變量與互斥量組合使用
- 互斥量為共享數據的訪問提供互斥支持
- 條件變量就狀態的變化向相關線程發出通知
# 三種操作方法
- 等待通知: wait
- 阻塞當前線程,直到收到該條件變量發來的通知
- 單發通知: signal
- 讓該條件變量向至少一個正在等待它的通知的線程發送通知,表示共享數據的狀態已經改變。
- 廣播通知: broadcast
- 讓條件變量給正在等待它的通知的所有線程都發送通知。
# 聲明
> func NewCond(l Locker) *Cond
# 示例
改造上一節的鎖使用代碼
Golang同步:鎖的使用案例詳解
傳送門:[http://blog.csdn.net/liuxinmingcode/article/details/50044327](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
}
~~~
因為一個數據塊只能有一個讀操作讀取,因此我們使用條件變量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](https://github.com/lxmgo/learngo)
- 前言
- golang學習(一)之安裝
- Go語言學習二:Go基礎(變量、常量、數值類型、字符串、錯誤類型)
- Go語言學習三:Go基礎(iota,array,slice,map,make,new)
- Go語言學習四:struct類型
- Ubuntu 14.04/CentOS 6.5中安裝GO LANG(GO語言)
- Mac OS 安裝golang
- Mac install Thrift
- Thrift RPC 使用指南實戰(附golang&PHP代碼)
- golang net/http包使用
- 冒泡排序Bubble sort-golang
- 快速排序Quick sort - golang
- Go語言學習:Channel是什么?
- Golang的select/非緩沖的Channel實例詳解
- Golang time包的定時器/斷續器
- Golang同步:鎖的使用案例詳解
- Golang同步:條件變量和鎖組合使用
- Golang同步:原子操作使用
- Golang之bytes.buffer
- Golang之字符串格式化
- Golang之反射reflect包
- Go語言配置文件解析器,類似于Windows下的INI文件.