仿照kfifo編寫乙個ring buffer

2021-06-28 20:18:32 字數 4680 閱讀 9396

/**@brief 仿照linux kfifo寫的ring buffer

*@atuher anker date:2013-12-18

* ring_buffer.h

* */

#ifndef kfifo_header_h

#define kfifo_header_h

#include #include #include #include #include #include //判斷x是否是2的次方

#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))

//取a和b中最小值

#define min(a, b) (((a) < (b)) ? (a) : (b))

struct ring_buffer

;//初始化緩衝區

struct ring_buffer* ring_buffer_init(void *buffer, uint32_t size, pthread_mutex_t *f_lock)

ring_buf = (struct ring_buffer *)malloc(sizeof(struct ring_buffer));

if (!ring_buf)

memset(ring_buf, 0, sizeof(struct ring_buffer));

ring_buf->buffer = buffer;

ring_buf->size = size;

ring_buf->in = 0;

ring_buf->out = 0;

ring_buf->f_lock = f_lock;

return ring_buf;

}//釋放緩衝區

void ring_buffer_free(struct ring_buffer *ring_buf)

free(ring_buf);

ring_buf = null;

}}//緩衝區的長度

uint32_t __ring_buffer_len(const struct ring_buffer *ring_buf)

//從緩衝區中取資料

uint32_t __ring_buffer_get(struct ring_buffer *ring_buf, void * buffer, uint32_t size)

//向緩衝區中存放資料

uint32_t __ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, uint32_t size)

uint32_t ring_buffer_len(const struct ring_buffer *ring_buf)

uint32_t ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, uint32_t size)

uint32_t ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, uint32_t size)

#endif

採用多執行緒模擬生產者和消費者編寫測試程式,如下所示:

/**@brief ring buffer測試程式,建立兩個執行緒,乙個生產者,乙個消費者。

* 生產者每隔1秒向buffer中投入資料,消費者每隔2秒去取資料。

*@atuher anker date:2013-12-18

* */

#include "ring_buffer.h"

#include #include #define buffer_size 1024 * 1024

typedef struct student_info

student_info;

void print_student_info(const student_info *stu_info)

student_info * get_student_info(time_t timer)

srand(timer);

stu_info->stu_id = 10000 + rand() % 9999;

stu_info->age = rand() % 30;

stu_info->score = rand() % 101;

print_student_info(stu_info);

return stu_info;

}void * consumer_proc(void *arg)

return (void *)ring_buf;

}void * producer_proc(void *arg)

return (void *)ring_buf;

}int consumer_thread(void *arg)

return tid;

}int producer_thread(void *arg)

return tid;

}int main()

buffer = (void *)malloc(buffer_size);

if (!buffer)

size = buffer_size;

ring_buf = ring_buffer_init(buffer, size, f_lock);

if (!ring_buf)

#if 0

student_info *stu_info = get_student_info(638946124);

ring_buffer_put(ring_buf, (void *)stu_info, sizeof(student_info));

stu_info = get_student_info(976686464);

ring_buffer_put(ring_buf, (void *)stu_info, sizeof(student_info));

ring_buffer_get(ring_buf, (void *)stu_info, sizeof(student_info));

print_student_info(stu_info);

#endif

printf("multi thread test.......\n");

produce_pid = producer_thread((void*)ring_buf);

consume_pid = consumer_thread((void*)ring_buf);

pthread_join(produce_pid, null);

pthread_join(consume_pid, null);

ring_buffer_free(ring_buf);

free(f_lock);

return 0;

}

總結:len = min(len, fifo->size - fifo->in + fifo->out); 

len(fifo->size - fifo->in + fifo->out)之間取乙個較小的值賦給len。注意,當(fifo->in == fifo->out+fifo->size)時,表示緩衝區已滿,此時得到的較小值一定是0,後面實際寫入的位元組數也全為0。

另一種邊界情況是當len很大時(因為len是無符號的,負數對它來說也是乙個很大的正數),這一句也能保證len取到乙個較小的值,因為fifo->in總是大於等於fifo->out,所以後面的那個表示式l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));的值不會超過fifo->size的大小。

smp_mb();  smp_wmb();是加記憶體屏障,這裡不是我們討論的範圍,你可以忽略它。 

l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));是把上一步決定的要寫入的位元組數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)的效果一樣。 

這樣後面的**就不難理解了,它先向  fifo->in  到緩衝區末端這一塊寫資料,如果還沒寫完,在從緩衝區頭開始寫入剩下的,從而實現了迴圈緩衝。最後,把寫指標後移 len 個位元組,並返回len。

從上面可以看出,fifo->in的值可以從0變化到超過fifo->size的數值,fifo->out也如此,但它們的差不會超過fifo->size。

編寫乙個makefile

什麼是makefile?對於大多數的windows程式設計師來講,makefile可能不是那麼重要,因為windows的ide都為程式設計師做好了這個工作。但是在linux下程式設計,會不會寫makefile,從側面上說明乙個人是否具備完成大型工程的能力。makefile的作用 makefile是用...

編寫乙個webpack loader

loader是一種打包的方案,webpack預設只識別js結尾的檔案,當遇到其他格式的檔案後,webpack並不知道如何去處理。此時,我們可以定義一種規則,告訴webpack當他遇到某種格式的檔案後,去求助於相應的loader。新建loaders資料夾並建立三個loaders檔案 remove co...

乙個簡單的程序 跳到ring3

typedef unsigned int u32 typedef unsigned short u16 typedef unsigned char u8 typedef struct descriptor 8 a?descriptor void set gdt desc struct desc st...