循环缓冲队列的思考

一般我们设置一个缓冲队列的结构如下
struct queue
{
uint16_t front; ///< 队列头指针
uint16_t rear; ///< 队列尾指针
uint16_t count; ///< 队列数据可以存储元素的个数
uint8_t *dat;//指向数据缓冲区的地址
}QUEUE;

这一类队列缓冲区只能进行单个字节的存储操作,而对多字节的结构体或32位的int操作,需要重新写重复的函数来实现,本来一次就能做好的事情非得让人做n次,是会很让人火气的,难道就没有个模板可以对各种类型的结构进行存储吗?就想c++的容器那样,只要定义了类型就可以用相同的函数直接操作,只是操作的对象不同,就可以实现不同效果的存储访问。

当然有,下面就来看这种队列结构,
struct queue
{
uint16_t front; ///< 队列头指针
uint16_t rear; ///< 队列尾指针
uint16_t count; ///< 队列数据可以存储元素的个数
uint8_t elem_size;//存放单个元素所占空间的大小
uint8_t *dat;//指向数据缓冲区的地址
uint16_t buffer_size;//数据缓冲区存储空间的大小
}QUEUE;

队列中定义了单个元素的存储空间的大小,其初始化函数如下:
QUEUE * queue_init(uint16_t elem_num,uint8_t elem_size);
elem_num为初始化队列的成员个数,elem_size为成员的所占空间的大小,以字节为单位.
如想定义int型的缓冲队列,成员100个,则xxxx_ptr=queue_init(100,sizeof(int));最后返回队列的缓冲区空间的首地址.
如想定义struct结构体类型的缓冲队列,成员100个,则
struct xxx xxxx_ptr= queue_init(100,sizeof(struct xxx));
但有时候我想对这个缓冲队列同时进行push in操作,但有时候程序代码又不知道什么时候进行了pop out操作,因为这种缓冲队列一般是互斥资源,不允许这样的操作,会很容易造成非法访问内存地址的错误,造成队列存储的损坏。
no作 no death,互斥资源是不能同时访问的,你自己作也没办法,估计有人会这么想,实际我也这么想过,嘿嘿.
但实际有时候,不是我们不想互斥的访问缓冲队列,而是迫不得己,例如我正在主函数中取缓冲队列的数据进行处理,恰好此时接收中断发生,需要向缓冲队列中存放数据,天哪,同时访问互斥资源缓冲队列的情况发生了,这哪是我想要的啊,天地可证。
那就加锁呗,这是个好方法吗?姑且试一下,对缓冲队列的处理部分加锁,但恰此时接收中断发生时,加了锁,就没法对接收缓冲区队列访问,你让我把数据往哪放,数据又不能丢弃.
怎么办?
再写个缓冲队列,临时存放接收的数据,等缓冲队列的处理结束后,我再把临时缓冲队列的数据copy到缓冲队列中,那对临时缓冲队列的pop out操作时,也有可能此时也发生了中断,那怎么操作,临时缓冲队列被上锁占用,往缓冲队列中存放数据,那接收数据的顺序不就乱了吗,怎么办,还是需要对一个缓冲队列同时进行push in和pop out操作,所谓的把队列作为互斥资源,是因为队列的结构体定义中,存在互斥的变量成员.
再看下缓冲队列的结构体定义
struct queue
{
uint16_t front; ///< 队列头指针
uint16_t rear; ///< 队列尾指针
uint16_t count; ///< 队列数据可以存储元素的个数
uint8_t elem_size;//存放单个数据所占空间的大小
uint8_t *dat;//指向数据缓冲区的地址
uint16_t buffer_size;//数据缓冲区存储空间的大小
}QUEUE;

看下是谁有可能被push in和pop out操作时同时访问,且会改变其值的成员变量,只有count,push in时,我要增加count的值,pop out时我要减少count的值。那下面就讨论下 如何做才能对互斥的count同时操作,而对缓冲队列没有任何危害。要么直接就把count这个成员变量直接拿掉,不要了。不要就不会有问题了。
结构就变成这样了
struct queue
{
uint16_t front; ///< 队列头指针
uint16_t rear; ///< 队列尾指针
bool is_empty;
uint8_t elem_size;//存放单个数据所占空间的大小
uint8_t *dat;//指向数据缓冲区的地址
uint16_t buffer_size;//数据缓冲区存储空间的大小
}QUEUE;

那现在的问题就是考虑一下下面两个问题。
1:队列的空满问题
对于队列的空满,用一个标志量is_empty变量表示,或浪费队列中一个存储空间表示
对于第一种方法,需要在每次对循环队列push in 和pop out操作退出前,都要对is_empty变量更改其值。(如果选择这种)
不可行,因为is_empty也是互斥的资源,需要在push in 和pop out操作中改变这个成员的值.
那只能选择最后一个方法:浪费一个存储空间的方法
queue_ptr->front ==(queue_ptr->rear+queue_ptr->elem_size)%queue_ptr->buffer_size;
即如果定义一个一个队列的存储值是COUNT,然其实际只能存储COUNT-1个值。

2:队列的存储长度获取问题
(queue_ptr->rear+queue_ptr->buffer_size-queue_ptr->front)%queue_ptr->buffer_size/ queue_ptr->elem_size;
通过对这个循环队列的操作,我们就可以同时对一个队列进行pop的操作时,也可以进行push操作,但是不允许两个pop操作或push操作同时发生。
参考代码:http://download.csdn.net/detail/u011018358/9527916

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值