by zn
在存取数据量较大的条件下,如果put的速度远快于get的速度导致环形缓冲区趋于满状态。在该状态下,环形缓冲区将无法一次性收够实际的数据量,则可能导致接收数据丢失。
因此,在使用环形缓冲区时应该尽快将数据取出(保证取数据速度大于存数据的速度),从而避免数据丢失的情况。
typedef struct
{
INT32S pToBuf; /* 可以写入数据的距buffer开始的偏移量——环形缓冲区存索引号*/
INT32S pFromBuf; /* 可以读数据的距buffer开始的偏移量——环形缓冲区取索引号*/
INT32S bufSize; /* 以字节为单位的环形buffer的大小*/
INT8S *buf; /* 指向buffer的开始处*/
}RING, *RING_ID;
(1)分配环形缓冲区结构体ringId
(2)分配环形缓冲区空间
因为环形缓冲区算法中至少有一个字节空间为空,所以需要比用户传入的空间大小多分配1字节的空间
RING_ID rngCreate(INT32S nbytes)
{
INT8S *buffer;
/*
(1)分配环形缓冲区结构体ringId
*/
RING_ID ringId = (RING_ID) malloc (sizeof (RING));
if(ringId == NULL)
return (NULL);
/*
(2)分配环形缓冲区空间
因为环形缓冲区算法中至少有一个字节空间为空,所以需要比用户传入的空间大小多分配1字节的空间
*/
buffer = (INT8S *) malloc ((INT32U) ++nbytes);
if(buffer == NULL)
{
free ((INT8S *)ringId);
return (NULL);
}
ringId->bufSize = nbytes;
ringId->buf = buffer;
rngFlush (ringId);
return (ringId);
}
(1)条件1:环形缓冲区取索引号大于存索引号。
此条件下可向环形缓冲区中存入的字节数为用户指定字节数与取索引号和存索引号之差减1的较小值。但是,如果取索引仅比存索引大1,则不能继续存放数据。
(2)条件2:取索引小于等于存索引且取索引为0。
该条件下可以存放的数据量为用户指定字节数与环形缓冲区大小与存索引号之差减1的较小值。
(3)条件3:取索引小于等于存索引且取索引不等于0。
该条件下要分两个情况进行处理。
情况1:如果用户指定的存放字节数大于缓冲区大小减去存索引的差,表示当前缓冲区不能一次存放待存数据,需要分两步进行存放。
步骤1:将环形缓冲区填满。
步骤2:重新比较剩余待存字节数与取索引-1的大小,继续存放其中的较小值的数据量,并调整存索引的值。
情况2:如果用户指定的存放字节数小于缓冲区大小减去存索引的差,表示当前缓冲区一次能够存放待存的数据。存入数据并更新存索引后返回即可。
INT32S rngBufPut(
RING_ID rngId, /* ring buffer to put data into */
INT8S *buffer, /* buffer to get data from */
INT32S nbytes /* number of bytes to try to put */
)
{
INT32S bytesput=0;
INT32S pFromBuf = rngId->pFromBuf;
INT32S bytes2=0;
INT32S pRngTmp=0;
if (pFromBuf > rngId->pToBuf)
{
/*
(1)条件1:环形缓冲区取索引号大于存索引号。此条件下可向环形缓冲区中存入的字节数为用户指定字节数与取索引号和存索引号之差减1的较小值。但是,如果取索引仅比存索引大1,则不能继续存放数据。
*/
bytesput = min (nbytes, pFromBuf - rngId->pToBuf - 1);
memcpy(&rngId->buf [rngId->pToBuf], buffer, bytesput);
rngId->pToBuf += bytesput;
} else if (pFromBuf == 0) {
/*
(2)条件2:取索引小于等于存索引且取索引为0。该条件下可以存放的数据量为用户指定字节数与环形缓冲区大小与存索引号之差减1的较小值。
*/
bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf - 1);
memcpy(&rngId->buf [rngId->pToBuf], buffer, bytesput);
rngId->pToBuf += bytesput;
} else {
/*
(3)条件3:取索引小于等于存索引且取索引不等于0。该条件下要分两个情况进行处理。
情况1:如果用户指定的存放字节数大于缓冲区大小减去存索引的差,表示当前缓冲区不能一次存放待存数据,需要分两步进行存放。
步骤1:将环形缓冲区填满。
步骤2:重新比较剩余待存字节数与取索引-1的大小,继续存放其中的较小值的数据量,并调整存索引的值。
情况2:如果用户指定的存放字节数小于缓冲区大小减去存索引的差,表示当前缓冲区一次能够存放待存的数据。存入数据并更新存索引后返回即可。
*/
bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf);
memcpy(&rngId->buf [rngId->pToBuf], buffer, bytesput);
pRngTmp = rngId->pToBuf + bytesput;
if(pRngTmp == rngId->bufSize) {
/*情况1 步骤2*/
bytes2 = min (nbytes - bytesput, pFromBuf - 1);
memcpy(rngId->buf, buffer + bytesput, bytes2);
rngId->pToBuf = bytes2;
bytesput += bytes2;
} else {
rngId->pToBuf = pRngTmp; /*情况2*/
}
}
return (bytesput);
}
(1)条件1:存索引大于等于取索引。
该条件下存入的字节量为用户指定最大字节数与取索引和存索引之间的最小值。
(2)条件2:存索引小于取索引。该条件下需要分两种情况进行处理。
情况1:如果用户指定的存放字节数大于缓冲区大小减去取索引的差,表示不能一次从缓冲区中取出所有数据,需要分两步进行取数据。
步骤1:取数据直至到达缓冲区末尾。
步骤2:重新比较剩余待取字节数与存索引的大小,继续取出其中的较小值的数据量,并调整取索引的值。
情况2:如果用户指定的存放字节数大于缓冲区大小减去取索引的差,表示能一次从缓冲区中取出所有数据。取出数据并更新取索引后返回即可。
INT32S rngBufGet(
RING_ID rngId, /* ring buffer to get data from */
INT8S *buffer, /* pointer to buffer to receive data */
INT32S maxbytes /* maximum number of bytes to get */
)
{
INT32S bytesgot=0;
INT32S pToBuf = rngId->pToBuf;
INT32S bytes2=0;
INT32S pRngTmp=0;
if(pToBuf >= rngId->pFromBuf)
{
/*
(1)条件1:存索引大于等于取索引。该条件下存入的字节量为用户指定最大字节数与取索引和存索引之间的最小值。
*/
bytesgot = min (maxbytes, pToBuf - rngId->pFromBuf);
memcpy(buffer, &rngId->buf [rngId->pFromBuf], bytesgot);
rngId->pFromBuf += bytesgot;
} else {
/* pToBuf has wrapped around. Grab chars up to the end of the
* buffer, then wrap around if we need to. */
/*
(2)条件2:存索引小于取索引。该条件下需要分两种情况进行处理。
情况1:如果用户指定的存放字节数大于缓冲区大小减去取索引的差,表示不能一次从缓冲区中取出所有数据,需要分两步进行取数据。
步骤1:取数据直至到达缓冲区末尾。
步骤2:重新比较剩余待取字节数与存索引的大小,继续取出其中的较小值的数据量,并调整取索引的值。
情况2:如果用户指定的存放字节数大于缓冲区大小减去取索引的差,表示能一次从缓冲区中取出所有数据。取出数据并更新取索引后返回即可。
*/
bytesgot = min (maxbytes, rngId->bufSize - rngId->pFromBuf);
memcpy(buffer, &rngId->buf [rngId->pFromBuf], bytesgot);
pRngTmp = rngId->pFromBuf + bytesgot;
/* If pFromBuf is equal to bufSize, we've read the entire buffer,
* and need to wrap now. If bytesgot < maxbytes, copy some more chars
* in now. */
if(pRngTmp == rngId->bufSize)
{
/*情况1 步骤2*/
bytes2 = min (maxbytes - bytesgot, pToBuf);
memcpy(buffer + bytesgot, rngId->buf, bytes2);
rngId->pFromBuf = bytes2;
bytesgot += bytes2;
} else
rngId->pFromBuf = pRngTmp; /*情况2*/
}
return (bytesgot);
}