环形队列

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

// 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 杭州

做一门精致,全面详细的 java数据结构与算法!!! 让天下没有难学的数据结构, 让天下没有难学的算法, 不吹不黑,我们的讲师及其敬业,可以看到课程视频,课件,代码的录制撰写,都是在深夜,如此用心,其心可鉴,他不掉头发,谁掉头发??? 总之你知道的,不知道的,我们都讲,并且持续更新,走过路过,不要错过,不敢说是史上最全的课程,怕违反广告法,总而言之,言而总之,这门课你值得拥有,好吃不贵,对于你知识的渴求,我们管够管饱 话不多说,牛不多吹,我们要讲的本门课程内容: 稀疏数组、单向队列环形队列、单向链表、双向链表、环形链表、约瑟夫问题、栈、前缀、中缀、后缀表达式、中缀表达式转换为后缀表达式、递归与回溯、迷宫问题、八皇后问题、算法的时间复杂度、冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、基数排序(桶排序)、堆排序、排序速度分析、二分查找、插值查找、斐波那契查找、散列、哈希表、二叉树、二叉树与数组转换、二叉排序树(BST)、AVL树、线索二叉树、赫夫曼树、赫夫曼编码、多路查找树(B树B+树和B*树)、图、图的DFS算法和BFS、程序员常用10大算法、二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法马踏棋盘算法。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页