队列实现(基于内存池思想)

1. 阅读公司代码的时候,发现公司代码向串口打印,先把数据加载到数组中,进入临界区,然后通过串口输出,退出临界区。

2. 当然还有向flash写数据,直接一次性原文写入,也没进入临界区,挂起任务调度,

3. 网络数据发送的时候,也是直接发送,而发送的数据量过大,已经出现好多关于网络发送时,芯片往接口丢数据过大,过快导致发送失败。

似乎所有的这种输入大于输出的问题,都会存在,如果强制关中断,或挂起任务调度,确实可以解决,但是我认为这样速度就下降了。

我想到的方法是,通过增加缓存,往缓存写入数据,但是我们必须清楚,大数据时缓存必定会满,这个时候肯定需要涉及动态内存申请(内存池,内存堆,可能内存池会对内存使用会造成一定的浪费,但是速度会很快)。

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

/*
1.定一个小

*/
typedef struct cache_simple {
	struct cache_simple* cache_next;
	unsigned int buf_len;
	unsigned char buf[0];
}cache_simple_t;

typedef struct cache{
	unsigned char* data_head;
	unsigned char* data_tail;
	unsigned int block_size;
	cache_simple_t* cache_next;
}cache_t;

void init_my_cache(cache_t* cache_head, unsigned int block_size)
{
	cache_simple_t* my_cache = (cache_t*)malloc(sizeof(cache_simple_t) + block_size);

	if (!my_cache) {
		return;
	}

	my_cache->buf_len = block_size;
	my_cache->cache_next = NULL;
	cache_head->cache_next = my_cache;
	cache_head->data_head = my_cache->buf;
	cache_head->data_tail = my_cache->buf;
	cache_head->block_size = block_size;
}

static void insert_cache(cache_t* cache_head, unsigned int size)//尾插
{
	cache_simple_t* p = cache_head->cache_next;

	cache_simple_t* new_cache = (cache_simple_t*)malloc(sizeof(cache_simple_t) + size);

	if (new_cache == NULL) {
		return;
	}

	while (p->cache_next) {
		p = p->cache_next;
	}
	p->cache_next = new_cache;
	new_cache->buf_len = size;
	new_cache->cache_next = NULL;
}

//static void delet_cache(cache_t* cache_head)//头删
//{
//	cache_simple_t* p = cache_head->cache_next;
//
//	if (p) {
//		cache_head->cache_next = p->cache_next;
//		free(p);
//	}
//}


void insert_data(cache_t* cache_head, unsigned char* buf, unsigned int len)
{
	cache_simple_t* p = cache_head->cache_next;
	cache_t* p_head = cache_head;
	unsigned int malloc_size;
	unsigned int block_num, i;

	while (p->cache_next){
		p = p->cache_next;
	}

	/* 数据尾指针总是指向最后, 如果要插入数据, 要计算申请多少块block_size的内存来存储 */
	if (p_head->data_tail + len > p->buf + p->buf_len) {
		malloc_size = len - (unsigned int)(p->buf + p->buf_len - p_head->data_tail);
		block_num = malloc_size / p_head->block_size + ((malloc_size % p_head->block_size) ? 1 : 0);
		for (i = 0; i < block_num; i++) {
			insert_cache(p_head, p_head->block_size);
		}
	}

	/* 将数据存入申请的内存中 */
	for (i = 0; i < len; i++) {
		*p_head->data_tail = buf[i];
		if (p_head->data_tail == p->buf + p_head->block_size -1) {
			p_head->data_tail = p->cache_next->buf;
			p = p->cache_next;
		} else {
			p_head->data_tail++;
		}
	}

}

void display_list(cache_t* cache)
{
	cache_simple_t* p = cache->cache_next;
	unsigned int i;
	while (p) {
		for (i = 0; i < cache->block_size; i++) {
			printf("%c ", p->buf[i]);
		}
		p = p->cache_next;
	}
}

unsigned int read_data(cache_t* cache, unsigned char* data)
{
	cache_simple_t* p = cache->cache_next;

	/* 如果数据头尾指针相等, 则此时链表中数据为空 */
	if (cache->data_head == cache->data_tail) {
		cache->data_head = cache->data_tail = cache->cache_next->buf;
		return 0;
	}

	/* 数据头指针指向的就是数据 */
	*data = *cache->data_head;
	/* 数据头指针必定在cache_head指向的第一结点 */
	if (cache->data_head == p->buf + cache->block_size - 1) {
		if (p->cache_next) {/* 只有当前结点的下一个结点不为空,才能将数据指针指向下一位置, 并删除当前这个结点 */
			cache->data_head = p->cache_next->buf;
			cache->cache_next = p->cache_next;
			free(p);
		}
	}
	else {
		cache->data_head++;
	}
	if (cache->data_head == cache->data_tail) {
		cache->data_head = cache->data_tail = cache->cache_next->buf;
	}
	return 1;
}
unsigned int read_ndata(cache_t* cache, unsigned char* data, unsigned int len) 
{
	unsigned int i, read_len = 0;
	for (i = 0; i < len; i++){
		if (read_data(cache, data + i)) {
			read_len++;
		}
	}
	return read_len;
}
char * str = "123456789qwertyuiopasdfghjkl";
char * str1 = "mnbvcxzlk";
void main()
{
	int i, len;
	unsigned char data[100];
	cache_t cache;
	init_my_cache(&cache, 10);

	insert_data(&cache, str, strlen(str));
	
	len = read_ndata(&cache, data, 28);
	for (i = 0; i < len; i++){
		printf("%c ", data[i]);
	}
	printf("\n");
	insert_data(&cache, str1, strlen(str1));
	display_list(&cache);

	while (1);
}

如果我们是单纯的写入数据, 串口打印,lwip发送这样没问题, 但是考虑到这个要用到对flash的操作, 意味着内部写入的数据, 要附带地址起始位置, 写入的数据, 数据长度,通通写道这个buf中, 然后底层接口读取的时候, 就需要获取这些信息, 并且读取数据

代码没在实际项目跑过, 并且这里面的内存分配malloc是有问题的, 如果是跑的裸机, 请使用我的另一篇内存池设计实现, 当然也可以把内存池跑到RTOS中, 或者直接使用RTOS的内存管理算法, 如果可以希望朋友们帮忙一起验证一下这篇和内存池.实际上内存池就是我打算设计给到这里来使用的.

这里实际就是一个队列的实现, 当数据一个一个入队, 当入队的数据满了一个预先申请的块, 则会重新申请相同大小的一块, 继续存储数据. 出队的时候, 一个数据一个数据的出, 当出完一个存储块, 则释放这段内存, 如果出到最后一块, 是不会把这块删除的, 同时如果队列为空了, 则链表指针会恢复到当前内存块的起始位置.

需要优化的地方:

1. 队列没有数据的时候,不应该分配内存

2.如下图,两种队列形式,第一种用于内部数据缓存与传递,空间利用率高,由于内部可控,处理方便;第二种用于外部数据缓存(串口), 一般数据都会以0x0d 0x0a结尾,证明接收到一帧数据,那我们久可以用strstr函数轻松比对数据了(在RTOS系统种用起来可能比较麻烦,互斥不能在中断中使用,临界区一直开关,可能导致数据接收不到)。

同样的freertos在内存分配的时候,也可能遇到同样的问题,不能再中断中分配内存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

入门->放弃

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

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

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

打赏作者

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

抵扣说明:

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

余额充值