环形队列

环形队列,也可以叫环形缓冲区。我们用数组来举例,通常对于一个放到数组中的队列,生产者将数据写入队尾,消费者从队头取走,两个指针朝着同一个方向运动,消费者追生产者。而“环”在这里的体现,就是不管生产者还是消费者,当指针跑到队尾的时候,掉头到该数组头去,形成一个没有终点的环。
这要做的好处是,当生产者和消费者都是单线程,也就是只有一个生产者和一个消费者的时候,不用加锁。如果生产者或者消费者都是多个,就要加锁了,那还不如用普通队列吧。
- 队空:生产者和消费者的指针在同一位置。
- 队满:生产者的指针比消费者的指针小一个单位的时候,下一步就将指向消费者。
环形缓冲区
以下是我的示例,采用数组的线性队列,当然你也可以使用链表,这里只说明原理,就不展出了。两个线程分别模拟生产者和消费者

// gcc test.c -lpthread
#include <stdio.h>
#include <pthread.h>
#include <string.h>

#define MAX 10
#define LENGTH 32

struct circular_queue{
    char status; /**< 0 队列可写 1队列满*/
    int write; /**< 写指针,只能生产者修改 */
    int read; /**< 读指针,只能消费者修改 */
    char queue[MAX][LENGTH];  /**< 环形队列,每个元素32字节最大长度 */
};

void print_queue(struct circular_queue *cq){
    int i = 0;
    printf("print all:write=%d,read=%d:", cq->write, cq->read);
    for(i = cq->read; i != cq->write; ){
        printf("queue[%d]=%s ", i, cq->queue[i]);
        i = ++i % MAX;
    }
    printf("\n");
}

void init_circular_queue(struct circular_queue *cq){
    memset(cq, 0, sizeof(struct circular_queue));
}

int put(struct circular_queue *cq, char* str, size_t strlen){
    if(cq->status == 1){ // 队列满,无法插入
        //perror("full");
        print_queue(cq);
        return -1;
    } else {
        memcpy(&cq->queue[cq->write], str, strlen);
        cq->queue[cq->write][strlen] = '\0'; // 不要忘了终结符
        printf("put queue[%d]=%s\n", cq->write, cq->queue[cq->write]);
        cq->write = (cq->write + 1) % MAX;
        if((cq->read - 1) == cq->write)
            cq->status = 1;
    }
    return 0;
}

char* get(struct circular_queue *cq){
    //printf("test_get:write=%d,read=%d:", cq->write, cq->read);
    if(cq->read == cq->write){ // 队列空
        return NULL;
    } else {
        int tmp = cq->read;
        cq->read = (cq->read + 1) % MAX;
        cq->status = 0;
        return cq->queue[tmp];
    }
}

void* producer(void *para){
    struct circular_queue *cq = (struct circular_queue*)para;
    while(1){
        put(cq, "abc", 3);
        sleep(1);
        put(cq, "1", 1);
        sleep(1);
        put(cq, "123456", 6);
        sleep(1);
        put(cq, "hello world!", 12);

    }

}
void* consumer(void *para){
    struct circular_queue *cq = (struct circular_queue*)para;
    while(1){
        printf("get %s\n", get(cq));
        sleep(2);
    }
}

int main(){
    pthread_t t1, t2;
    struct circular_queue cq;
    init_circular_queue(&cq);
    // 启动生产者线程
    if(pthread_create(&t1, NULL, producer, &cq)){
        perror("producer");
    }
    // 启动消费者线程
    if(pthread_create(&t2, NULL, consumer, &cq)){
        perror("consumer");
    }
    while(1){}
    return 0;
}

运行结果

get (null)
put queue[0]=abc
put queue[1]=1
get abc
put queue[2]=123456
put queue[3]=hello world!
put queue[4]=abc
get 1
put queue[5]=1
put queue[6]=123456
get 123456
put queue[7]=hello world!
put queue[8]=abc
put queue[9]=1
get hello world!
put queue[0]=123456
put queue[1]=hello world!
put queue[2]=abc
get abc
put queue[3]=1
queue full: Success
print all:write=4,read=5:queue[5]=1 queue[6]=123456 queue[7]=hello world! queue[8]=abc queue[9]=1 queue[0]=123456 queue[1]=hello world! queue[2]=abc queue[3]=1 
get 1
put queue[4]=hello world!
queue full: Success
print all:write=5,read=6:queue[6]=123456 queue[7]=hello world! queue[8]=abc queue[9]=1 queue[0]=123456 queue[1]=hello world! queue[2]=abc queue[3]=1 queue[4]=hello world! 
queue full: Success
print all:write=5,read=6:queue[6]=123456 queue[7]=hello world! queue[8]=abc queue[9]=1 queue[0]=123456 queue[1]=hello world! queue[2]=abc queue[3]=1 queue[4]=hello world! 
get 123456
put queue[5]=123456
queue full: Success
print all:write=6,read=7:queue[7]=hello world! queue[8]=abc queue[9]=1 queue[0]=123456 queue[1]=hello world! queue[2]=abc queue[3]=1 queue[4]=hello world! queue[5]=123456 
queue full: Success
print all:write=6,read=7:queue[7]=hello world! queue[8]=abc queue[9]=1 queue[0]=123456 queue[1]=hello world! queue[2]=abc queue[3]=1 queue[4]=hello world! queue[5]=123456 
get hello world!
put queue[6]=1
queue full: Success
print all:write=7,read=8:queue[8]=abc queue[9]=1 queue[0]=123456 queue[1]=hello world! queue[2]=abc queue[3]=1 queue[4]=hello world! queue[5]=123456 queue[6]=1 
get abc
put queue[7]=hello world!
queue full: Success
print all:write=8,read=9:queue[9]=1 queue[0]=123456 queue[1]=hello world! queue[2]=abc queue[3]=1 queue[4]=hello world! queue[5]=123456 queue[6]=1 queue[7]=hello world! 
queue full: Success
print all:write=8,read=9:queue[9]=1 queue[0]=123456 queue[1]=hello world! queue[2]=abc queue[3]=1 queue[4]=hello world! queue[5]=123456 queue[6]=1 queue[7]=hello world! 
get 1
put queue[8]=123456
put queue[9]=hello world!
put queue[0]=abc
get abc
put queue[1]=1
put queue[2]=123456
get 1
put queue[3]=hello world!
put queue[4]=abc

可以看到队列从queue[0]到queue[9]一直在被循环使用,达到了环的目的,而且,不冲突,不用加锁!


创建于2011-09-30 深圳腾讯,更新于 2016-07-08 杭州

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值