本文最后更新于:2 个月前
完整代码详见GitHub CyclicBuffer。
什么是循环缓冲区
循环缓冲区通常应用在模块与模块之间的通信,可以减少程序挂起的时间,节省内存空间。
如图所示,蓝色箭头表示读取指针,红色表示写入指针。写入指针可以在缓冲区有剩余空间时不中断地写入数据,读取指针可以在循环缓冲区有数据时不停读取。
如何设计循环缓冲区
为了方便两个进程之间的通信,我们在共享内存中创建循环缓冲区。基本原理如图:
结构体定义
1 2 3 4 5 6 7
| typedef struct CyclicBuffer { uint8_t buf[CYCBUFFSIZ]; uint8_t read; uint8_t write; uint32_t valid_size; } CyCBuf;
|
写入数据
1 2 3 4 5 6 7 8 9
| void cycbuff_write(CyCBuf *cycbuff, uint8_t ch) { while (cycbuff_isfull(cycbuff)) ; cycbuff->buf[cycbuff->write] = ch; cycbuff->write++; cycbuff->write %= CYCBUFFSIZ; cycbuff->valid_size++; }
|
写入数据前,要检查缓冲区是否已满,如果已满就得挂起等待。直到缓冲区有空间再进行写入。
写入指针每次写完向后偏移一位,valid_size
记录当前缓冲区中有效数据个数。
读取数据
1 2 3 4 5 6 7 8 9 10 11
| uint8_t cycbuff_read(CyCBuf *cycbuff) { uint8_t ch; while (cycbuff_isempty(cycbuff)) ; ch = cycbuff->buf[cycbuff->read]; cycbuff->read++; cycbuff->read %= CYCBUFFSIZ; cycbuff->valid_size--; return ch; }
|
读取数据前,要检查缓冲区是否为空,如果为空就要挂起等待。
判断空
1 2 3 4 5 6
| bool cycbuff_isempty(CyCBuf *cycbuff) { if (cycbuff->valid_size == 0) return true; return false; }
|
判断满
1 2 3 4 5 6
| bool cycbuff_isfull(CyCBuf *cycbuff) { if (cycbuff->valid_size == CYCBUFFSIZ) return true; return false; }
|
本次实验中,为了方便期间,用valid_size
保存有效数据个数,没有用读写指针是否重合来判断,这就无需再考虑读写指针重合时,是空还是满。
数据收发流程
服务端-写入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void server(CyCBuf *cycbuff, SHMS *shms) { cycbuff_init(cycbuff); while (1) { puts("Enter Message: "); uint8_t ch[BUFFERSIZE]; fgets(ch, BUFFERSIZE, stdin); for (size_t i = 0; ch[i] != '\n' && i < BUFFERSIZE; i++) { cycbuff_write(cycbuff, ch[i]); } cycbuff_write(cycbuff, '\n'); } exit(0); }
|
SHMS *shms
为共享内存相关数据,有关共享内存的使用可以参考进程间通信(IPC)之共享内存(SharedMemory)。
客户端-读取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void client(CyCBuf *cycbuff, SHMS *shms) { printf("Server operational: shm id is %d\n", shms->shmid); while (1) { uint8_t ch; puts("Recv Message: "); while (1) { ch = cycbuff_read(cycbuff); if (ch == '\n') { printf("\n"); break; } fflush(stdout); printf("%c", ch); } } }
|
读取数据以回车符为分界,当读到回车符时进行换行处理,并等待接收下一波数据。
实验结果
Reference
Circular buffer