vxworks环形缓冲区函数源码分析

VxWorks环形缓冲区函数源码分析

​ by zn

0.使用环形缓冲区的注意事项

在存取数据量较大的条件下,如果put的速度远快于get的速度导致环形缓冲区趋于满状态。在该状态下,环形缓冲区将无法一次性收够实际的数据量,则可能导致接收数据丢失。

因此,在使用环形缓冲区时应该尽快将数据取出(保证取数据速度大于存数据的速度),从而避免数据丢失的情况。

1.环形缓冲区结构体定义

typedef struct			
{
    INT32S pToBuf;		/* 可以写入数据的距buffer开始的偏移量——环形缓冲区存索引号*/
    INT32S pFromBuf;	/* 可以读数据的距buffer开始的偏移量——环形缓冲区取索引号*/
    INT32S bufSize;		/* 以字节为单位的环形buffer的大小*/
    INT8S *buf;			/* 指向buffer的开始处*/
}RING, *RING_ID;

2.rngCreate——创建环形缓冲区

(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);
}

3.rngBufPut——向环形缓冲区中放入数据

(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);
}

4.rngBufGet——从环形缓冲区中获取数据

(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);
}
  • 8
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
VxWorks下,snprintf函数用于将格式化的数据写入指定的缓冲区。它的函数原型如下: ```c int snprintf(char *str, size_t size, const char *format, ...); ``` 其中,参数str是指向目标缓冲区的指针,size是目标缓冲区的大小,format是格式化字符串,后面的参数是可变参数,用于填充格式化字符串中的占位符。 要指定缓冲区,你需要确保目标缓冲区的大小足够容纳格式化后的数据。在调用snprintf函数之前,你需要先创建一个足够大的缓冲区,并将其地址传递给str参数。同时,你还需要指定缓冲区的大小,以确保不会发生缓冲区溢出。 下面是一个示例代码,演示了如何在VxWorks下使用snprintf函数指定缓冲区: ```c #include <stdio.h> #define BUFFER_SIZE 100 int main() { char buffer[BUFFER_SIZE]; int value = 42; // 使用snprintf函数将格式化后的数据写入缓冲区 int result = snprintf(buffer, BUFFER_SIZE, "The value is: %d", value); if (result >= 0 && result < BUFFER_SIZE) { printf("Formatted string: %s\n", buffer); } else { printf("Error: Buffer overflow!\n"); } return 0; } ``` 在上述示例中,我们创建了一个大小为100的缓冲区buffer,并将其地址传递给snprintf函数的str参数。然后,我们使用格式化字符串"The value is: %d"将变量value的值填充到缓冲区中。最后,我们根据snprintf函数的返回值判断是否发生了缓冲区溢出,并打印出格式化后的字符串。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weekman93

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值