使用slice和條件變數實現一個簡單的多生產者多消費者佇列

chasiny發表於2018-06-15

使用 slice 和條件變數實現一個簡單的多生產者多消費者佇列

源部落格地址
專案程式碼

設計要求

  • 多生產者,多消費者
  • 生產時若緩衝區以滿,則寫入阻塞
  • 消費時若緩衝區為空,則讀取等待

設計思路

結構體

首先定義佇列結構體

type MessageQueue struct {

    msgdata []interface{}       //緩衝區
    len     int32               //緩衝區長度

    readPos int32               //讀取指向的指標
    readMutex sync.Mutex        //讀取鎖

    writePos int32              //寫入指向的指標
    writeMutex sync.Mutex       //寫入鎖

    emptyCond *sync.Cond        //緩衝區為空條件變數
    fullCond  *sync.Cond        //緩衝區為滿條件變數
}

這裡使用的緩衝區是一個環形佇列

寫入的方法 (Put)

func (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] = in
    mq.writePos = (mq.writePos + 1) % mq.len

    //通知消費者已經有緩衝區有資料了
    mq.emptyCond.Signal()
}

讀取的方法 (Get)

func (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)

func 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)

func (mq *MessageQueue) Len() int32 {
    if mq.writePos < mq.readPos {
        return mq.writePos + mq.len - mq.readPos
    }

    return mq.writePos - mq.readPos
}
更多原創文章乾貨分享,請關注公眾號
  • 使用slice和條件變數實現一個簡單的多生產者多消費者佇列
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章