1. 程式人生 > >環形緩衝區的C語言實現

環形緩衝區的C語言實現

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <pthread.h>  

#define BUFFSIZE 1024 * 1024  
#define min(x, y) ((x) < (y) ? (x) : (y))  

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;  

struct cycle_buffer {  
    unsigned char *buf;  
    unsigned int size;  
    unsigned int in;  
    unsigned int out;  
    pthread_mutex_t lock;  
};  

static struct cycle_buffer *fifo = NULL;  

static int init_cycle_buffer(void)  
{
    int size = BUFFSIZE, ret;  

    ret = size & (size - 1);  
    if (ret)  
        return ret;
    fifo = (struct cycle_buffer *) malloc(sizeof(struct cycle_buffer));  
    if (!fifo)  
        return -1;  

    memset(fifo, 0, sizeof(struct cycle_buffer));  
    fifo->size = size;  
    fifo->in = fifo->out = 0;  
    pthread_mutex_init(&fifo->lock, NULL);  
    fifo->buf = (unsigned char *) malloc(size);  
    if (!fifo->buf)
        free(fifo);
    else
        memset(fifo->buf, 0, size);  
    return 0;  
}  

unsigned int fifo_get(unsigned char *buf, unsigned int len)  
{  
    unsigned int l;  
    len = min(len, fifo->in - fifo->out);  
    l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));  
    memcpy(buf, fifo->buf + (fifo->out & (fifo->size - 1)), l);  
    memcpy(buf + l, fifo->buf, len - l);  
    fifo->out += len;  
    return len;  
}  

unsigned int fifo_put(unsigned char *buf, unsigned int len)  
{  
    unsigned int l;  
    len = min(len, fifo->size - fifo->in + fifo->out);  
    l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));  
    memcpy(fifo->buf + (fifo->in & (fifo->size - 1)), buf, l);  
    memcpy(fifo->buf, buf + l, len - l);  
    fifo->in += len;  
    return len;  
}  

static void * thread_read(void *arg)  
{  
    char buf[1024];  
    unsigned int n;  
    pthread_detach(pthread_self());  
    for (;;) {  
        memset(buf, 0, sizeof(buf));  
        pthread_mutex_lock(&fifo->lock);  
        n = fifo_get(buf, sizeof(buf));  
        pthread_mutex_unlock(&fifo->lock);  
        write(STDOUT_FILENO, buf, n);  
    }
    printf("nnafter thread_read : %snn",buf);
    return NULL;  
}  

static void * thread_write(void *arg)  
{  
    unsigned char buf[] = "hello world";  
    pthread_detach(pthread_self());  
    for (;;) {  
        pthread_mutex_lock(&fifo->lock);  
        fifo_put(buf, strlen(buf));  
        pthread_mutex_unlock(&fifo->lock);  
    }  
    return NULL;  
}  

int main(void)  
{  
    int ret;  
    pthread_t wtid, rtid;  
    ret = init_cycle_buffer();  
    if (ret == -1)  
        return ret;  

    pthread_create(&wtid, NULL, thread_write, NULL);  
    pthread_create(&rtid, NULL, thread_read, NULL);  
    pthread_exit(NULL);  
    return 0;
}


  1. buffer指向存放資料的緩衝區,size是緩衝區的大小,
    in是寫指標下標,out是讀指標下標,在len和(fifo->size - fifo->in + fifo->out)之間取一個較小的值賦給len。注意,當(fifo->in == fifo->out+fifo->size)時,表示緩衝區已滿,此時得到的較小值一定是0,後面實際寫入的位元組數也全為0。另一種邊界情況是當len很大時(因為len是無符號的,負數對它來說也是一個很大的正數),這一句也能保證len取到一個較小的值,因為fifo->in總是大於等於fifo->out,所以後面的那個表示式的值不會超過fifo->size的大小把上一步決定的要寫入的位元組數len“切開”,這裡又使用了一個技巧。注意:實際分配給fifo->buffer的位元組數fifo->size,必須是2的冪,否則這裡就會出錯。既然fifo->size是2的冪,那麼 (fifo->size-1)也就是一個後面幾位全為1的數,也就能保證(fifo->
    in & (fifo->size - 1))總為不超過(fifo->size - 1)的那一部分,和(fifo->in)% (fifo->size - 1)的效果一樣。  
  2. 這樣後面的程式碼就不難理解了,它先向fifo->in到緩衝區末端這一塊寫資料,如果還沒寫完,在從緩衝區頭開始寫入剩下的,從而實現了迴圈緩衝。最後,把寫指標後移len個位元組,並返回len。
  3. 從上面可以看出,fifo->in的值可以從0變化到超過fifo->size的數值,fifo->out也如此,但它們的差不會超過fifo->size 。
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script> 閱讀(1) | 評論(0) | 轉發(0) | 0

下一篇:c疑難點

給主人留下些什麼吧!~~ 評論熱議