使用slice和條件變數實現一個簡單的多生產者多消費者隊列
來源:互聯網
上載者:User
# 使用slice和條件變數實現一個簡單的多生產者多消費者隊列## [源部落格地址](https://github.com/Chasiny/Blog/blob/master/blog/go/%E4%BD%BF%E7%94%A8slice%E5%92%8C%E6%9D%A1%E4%BB%B6%E5%8F%98%E9%87%8F%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E5%A4%9A%E7%94%9F%E4%BA%A7%E8%80%85%E5%A4%9A%E6%B6%88%E8%B4%B9%E8%80%85%E9%98%9F%E5%88%97.md) ## [項目代碼](https://github.com/Chasiny/Blog/tree/master/code/go/message_queue)## 設計要求* 多生產者,多消費者 * 生產時若緩衝區以滿,則寫入阻塞 * 消費時若緩衝區為空白,則讀取等待## 設計思路### 結構體首先定義隊列結構體```gotype MessageQueue struct {msgdata []interface{}//緩衝區len int32//緩衝區長度readPos int32//讀取指向的指標readMutex sync.Mutex//讀取鎖writePos int32//寫入指向的指標writeMutex sync.Mutex//寫入鎖emptyCond *sync.Cond//緩衝區為空白條件變數fullCond *sync.Cond//緩衝區為滿條件變數}```這裡使用的緩衝區是一個環形隊列### 寫入的方法(Put)```gofunc (mq *MessageQueue) Put(in interface{}) {//首先擷取寫鎖,所有寫入的優先順序是一樣的mq.writeMutex.Lock()defer mq.writeMutex.Unlock()//判斷緩衝區是否為滿mq.fullCond.L.Lock()defer mq.fullCond.L.Unlock()for (mq.writePos+1)%mq.len == mq.readPos {//緩衝區為滿,等待消費者消費的通知緩衝區有資料被取出mq.fullCond.Wait()}//寫入一個資料mq.msgdata[mq.writePos] = inmq.writePos = (mq.writePos + 1) % mq.len//通知消費者已經有緩衝區有資料了mq.emptyCond.Signal()}```### 讀取的方法(Get)```gofunc (mq *MessageQueue) Get() (out interface{}) {//擷取讀鎖,讀取的優先順序也是一樣的mq.readMutex.Lock()defer mq.readMutex.Unlock()//判斷緩衝區是否為空白mq.emptyCond.L.Lock()defer mq.emptyCond.L.Unlock()for mq.writePos == mq.readPos {//緩衝區為空白,等待生產者通知緩衝區有資料存入mq.emptyCond.Wait()}//讀取out = mq.msgdata[(mq.readPos)%mq.len]mq.readPos = (mq.readPos + 1) % mq.len//通知生產者已經有緩衝區有空間了mq.fullCond.Signal()return}```### New方法(New)```gofunc NewMQ(len int32) *MessageQueue {if len < 1 {panic("new meg queue fail: len < 1")return nil}l:=&sync.Mutex{}return &MessageQueue{msgdata: make([]interface{}, len+1),len: len + 1,readPos: 0,writePos: 0,emptyCond: sync.NewCond(l),fullCond: sync.NewCond(l),}}```### 長度(Len)```gofunc (mq *MessageQueue) Len() int32 {if mq.writePos < mq.readPos {return mq.writePos + mq.len - mq.readPos}return mq.writePos - mq.readPos}```145 次點擊