环形队列,首先贴上介绍说明
https://baike.baidu.com/item/%E5%BE%AA%E7%8E%AF%E9%98%9F%E5%88%97/3685773?fr=aladdin
环形队列也叫循环队列,是一块首尾相接的圆环,通过首尾两个指针的移动来实现对队列成员的操作。
环形队列无需使用锁可以实现两个线程(生产者->消费者)读写。
实现环形队列的关键 是实现判断队列满,队列空。
废话不多说。
首先定义结构
type CircleBuffer struct {
Name string //名称
Mask uint32
Size uint32 //buf大小
In uint32 //入队列指针
Out uint32 //出队指针
Buf []byte //
}
初始化函数
func (cb *CircleBuffer) Init(name string,power uint32) {
cb.Name = name
cb.Size = 1 << power
cb.Mask = cb.Size - 1
cb.Buf = make([]byte,cb.Size)
cb.In = 0
cb.Out = 0
}
获取数据长度&空闲空间长度
func (cb *CircleBuffer) GetDataLen() uint32 {
if cb.In >= cb.Out {
return (cb.In - cb.Out)
}
return (cb.Size -(cb.In - cb.Out))
}
func (cb *CircleBuffer) GetFreeLen() uint32 {
if cb.In >= cb.Out {
return (cb.Size -(cb.In - cb.Out))
}
return (cb.Out - cb.In)
}
读写实现
func (cb *CircleBuffer) Read(buf *[]byte, len uint32) uint32 {
if cb.GetDataLen() <len {
return 0
}
if len <= 0{
return 0
}
//连续内存拷贝
if cb.In >= cb.Out {
copy(*buf , cb.Buf[cb.Out:cb.Out+len])
}else {
if len <= (cb.Size - cb.Out) {
copy(*buf, cb.Buf[cb.Out:cb.Out+len])
}else {
//head part
copy(*buf , cb.Buf[cb.Out:cb.Size])
//tail part
copy((*buf)[(cb.Size - cb.Out):len], cb.Buf[0:(len-(cb.Size - cb.Out))])
}
}
cb.offsetOut(len)
return len
}
func (cb *CircleBuffer) write(buf *[]byte, len uint32) uint32 {
if cb.GetFreeLen() < len {//空间不足
return 0
}
if len <= 0{
return 0
}
//连续内存拷贝
if cb.In >= cb.Out {
if len <= (cb.Size - cb.In) {
copy(cb.Buf[cb.In:] , *buf)
}else {
copy(cb.Buf[cb.In:], (*buf)[:(cb.Size - cb.In)])
copy(cb.Buf, (*buf)[(cb.Size - cb.In):])
}
}else {
copy(cb.Buf[cb.In:], *buf)
}
cb.offsetIn(len)
return len
}
测试函数
func main() {
cirBuf := new(CircleBuffer)
// 2^10 =1024
cirBuf.Init("test",10)
mychan := make(chan int,1)
//生产者
go func() {
for {
data:=[]byte("hello world 你好.....sssss")
cirBuf.write(&data, uint32(len(data)))
mychan <-1
//time.Sleep(300)
}
}()
//消费者
go func() {
for {
data:=make([]byte,12)
<- mychan
len := cirBuf.Read(&data, 12)
if len != 0 {
fmt.Println(string(data))
}
//time.Sleep(3000)
}
}()
for {
time.Sleep(5*time.Second)
fmt.Println(cirBuf.In)
fmt.Println(cirBuf.Out)
fmt.Println(cirBuf.Size)
fmt.Println(cirBuf.Mask)
}
}