单链表、内存池应用-消息抑制表的应用

2023-05-16

1.消息抑制表

设备之间进行源源不断的收和发送的时候,为保证数据的不丢包,由于延迟,拥塞或者其他情况,往往需要超时重发,大数据的交互,有这样一种需求:为保证消息的唯一性,需要对对一个消息的接受进行判断,判断是否对刚接收到消息进行处理或者进行抑制(直接丢掉不处理);

因为是海量大数据,需要对接收到的每一条消息进行建表动态缓存---即消息抑制表;

建表过程,分几种情况(没有绝对性,仅供参考)

(1)如果消息的生命周期很短(消息完成使命的时间) ,辨识信息短       可以数组来记录

(2)如果辨识信息较大-占用内存大,可以使用malloc动态分配和free释放

(3)如果消息生命周期长,辨识信息较大-;频繁(我是5ms)动态申请内存,造成碎片就不合适,需要使用内存池来进行

2.内存池

内存池的使用,可以为系统稳定性带来好处,有名的案例是Nginx服务器---低内存/高并发的性能,其中使用了双向链表+内存池的行为;
双向链表的好处,是在表中进行删除的时候非常方便--O(1)的复杂度;当然也有弊端(因此也有人用堆来做)
内存池的好处是,是在有限的内存中实现最大利用,避免了系统内存碎片!

3.具体实现(测试代码见最后)

在程序中使用内存时,都由内存池进行分配,不再使用的内存交给内存池回收,用于再次分配。

内存池一般会有如下的接口:
memory_pool_init, memory_pool_malloc, memory_pool_free 和 memory_pool_destroy;
内存池结构:

  • Memory_Pool: 用于内存属性结构,用于整个内存池的管理
  • Memory_Map_Table: 内存映射表,是Memory的映射,用于管理Memory
  • Memory_Alloc_Table: 内存分配表,用于记录分配过的内存
  • Memory:实际用于分配的内存

为辅助看懂我的代码,如下是我所使用的具体内存池布局:

定义的数据结构(队列节点和队列的定义)

我要做的功能,要根据情况,根据入队信息进行匹配,匹配成功,踢出内存池;否则内存池要根据更新情况,自动的出队和入队
定义内存池中队列数量为5的测试情况,验证:
 
68-78-88-98-a8内存的出入队的变化;验证情况有效!
具体代码(可以直接点击链接---下载测试工程):

 mem_pool.h

#ifndef __MEMORY_POOL_H__
#define __MEMORY_POOL_H__
 
#define MAX_POOL_SIZE 1024 * 1024
#define  BLOCK_SIZE 16
// #define BLOCK_SIZE 12//64
 
typedef struct memory_map_talbe
{
	char *p_block;
	int index;
	int used;
} Memory_Map_Table;//Memory_Map_Table: 内存映射表,是Memory的映射,用于管理Memory
 
typedef struct memory_alloc_table
{
	char *p_start;
	int used;
	int block_start_index;	//块首地址
	int block_cnt;
}Memory_Alloc_Table;//Memory_Alloc_Table: 内存分配表,用于记录分配过的内存
 
typedef struct memory_pool
{
	char *memory_start;					//内存池起始地址, free整个内存池时使用
	Memory_Alloc_Table *alloc_table;//用于记录分配过的内存
	Memory_Map_Table *map_table;	//用于管理Memory
	int total_size;				//内存池的总数量
	int internal_total_size;
	int increment;
	int used_size;				//内存池已用的数量
	int block_size;
	int block_cnt;
	int alloc_cnt;//分配数量
} Memory_Pool;//Memory_Pool: 用于内存属性结构,用于整个内存池的管理
 
extern Memory_Pool *memory_pool_init(int size, int increment);
extern void *Memory_malloc(Memory_Pool *pool, int size);
extern void memory_free(Memory_Pool *pool, void *memory);
extern void memory_pool_destroy(Memory_Pool *pool);
 
#endif

 tab_queue.h

#ifndef __TAB_QUEUE__
#define __TAB_QUEUE__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#define MAX_QUEUE_NUM 1000
#define base_queue_insert_head(h, x)		\
	(x)->next = (h)->next;			\
	(x)->next->prev = x;			\
	(x)->prev = h;				\
	(h)->next = x
typedef struct {
    __uint32_t time;    //0->....
    __uint8_t source_id;//0-64
    __uint8_t obj_id;   //0-8
    __uint8_t flag;     //0 1
    __uint8_t res;     //0 1
    // __uint32_t timeout;
    // __uint8_t date[16];
}OBJ_STRU;
#define ElemType OBJ_STRU
typedef struct QNode
{
    // char *memory;
    ElemType data;//定义队列中的元素
    struct QNode *next;
}QNode;
 
typedef struct LinkQueue
{
    QNode *front;
    QNode *rear;
}LinkQueue;//定义一个队列,队列只有一个头指针和一个尾指针
void InitQueue(LinkQueue *q);
int QueueLength(LinkQueue Q);
void *FindElem(LinkQueue *Q, ElemType e);
// int FindElem(LinkQueue *Q, ElemType e);
void InsertQueue(LinkQueue *p,ElemType *e);
void DeleteQueue(LinkQueue *p,ElemType *e);
void DestoryQueue(LinkQueue *p);
int QueueTraverse(LinkQueue Q);

#endif // !__TAB_QUEUE__

 mem_pool.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "mem_pool.h"
//获取内存映射表的位置
Memory_Map_Table *map_table_pos(Memory_Pool *pool)
{
	Memory_Map_Table *p = (Memory_Map_Table *)(pool->memory_start + sizeof(Memory_Pool));
	return p;
}
//获取内存分配表的位置
Memory_Alloc_Table *alloc_talbe_pos(Memory_Pool *pool)
{
	Memory_Alloc_Table *p = (Memory_Alloc_Table *)(pool->memory_start + sizeof(Memory_Pool) +
			sizeof(Memory_Map_Table) * (pool->block_cnt));
	return p;
} 

//获得memory在位置
char *memory_pos(Memory_Pool *pool)
{
	char *p = (char *)(pool->memory_start + sizeof(Memory_Pool) +
			(sizeof(Memory_Map_Table) + sizeof(Memory_Alloc_Table))* pool->block_cnt);
	return p;
}
 
Memory_Pool *memory_pool_init(int size, int increment)
{
	char *p = NULL;
	char *p_memory = NULL;
	Memory_Pool *pool = NULL;
	Memory_Alloc_Table *alloc_table = NULL;
	Memory_Alloc_Table *p_alloc_table = NULL;
	Memory_Map_Table *map_table = NULL;	
	Memory_Map_Table *p_map_table = NULL;
	int block_cnt = 0;
	int all_size = 0;
	int i = 0;
 
	if (size < 0 || size > MAX_POOL_SIZE) {
		printf("memory_pool_init(): Invalid size(%d)\n", size);
		return pool;
	}
 
	block_cnt = ((size + BLOCK_SIZE - 1) / BLOCK_SIZE);
	all_size = sizeof(Memory_Pool) + (sizeof(Memory_Map_Table) +sizeof(Memory_Alloc_Table)) * block_cnt + size;
	p = (char *)malloc(all_size);
	if (p == NULL) 
	{
		perror("Malloc failed\n");
		return pool;
	}
 
	memset(p, 0, all_size);
 
	pool = (Memory_Pool *)p;		//内存池的首地址
	pool->block_cnt = block_cnt;	//块数
	pool->block_size = BLOCK_SIZE;	//每个块大小
	pool->increment = increment;	//每块间增加大小
	pool->internal_total_size = BLOCK_SIZE * block_cnt;//每个块大小 * 每块间增加大小 =全部增加的大小
	pool->total_size = size;		//块总大小
	pool->used_size = 0;
	pool->alloc_cnt = 0;
	pool->memory_start = p;
 
	p_memory = memory_pos(pool);
	map_table = map_table_pos(pool);
	for (i = 0; i < block_cnt; i++) 
    {
		p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
		p_map_table->index = 0;
		p_map_table->p_block = p_memory + i * BLOCK_SIZE;
		p_map_table->used = 0;
	}
 
	alloc_table = alloc_talbe_pos(pool);
	for (i = 0; i < block_cnt; i++) 
    {
		p_alloc_table = (Memory_Alloc_Table *)((char *)alloc_table + i * sizeof(Memory_Alloc_Table));
		p_alloc_table->block_cnt = 0;
		p_alloc_table->block_start_index = -1;
		p_alloc_table->p_start = NULL;
		p_alloc_table->used = 0;
	}
 
	printf("memory_pool_init: total size: %d, block cnt: %d, block size: %d\n",
			pool->total_size, pool->block_cnt, BLOCK_SIZE);
	return pool;
}
 
void *Memory_malloc(Memory_Pool *pool, int size)
{
	char *p_start = NULL;
	int need_block_cnt = 0;
	Memory_Map_Table *map_table = NULL;
	Memory_Map_Table *p_map_table = NULL;
	Memory_Alloc_Table *alloc_table = NULL;
	Memory_Alloc_Table *p_alloc_table = NULL;
	int block_cnt = 0;
	int start_index = -1;
	int i = 0;
 
	if (size <= 0) 
	{
		printf("Invalid size(%d)\n", size);
		return p_start;
	}
 
	if (size > pool->total_size) 
	{
		printf("%d is more than total size\n", size);
		return p_start;
	}
 
	if (size > pool->total_size - pool->used_size) 
	{
		printf("Free memory(%d) is less than allocate(%d)\n",
		pool->total_size - pool->used_size, size);
		return NULL;
	}
 
	need_block_cnt = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;//需要分配的总块数
	map_table = map_table_pos(pool);
	printf("nend_cnt=%d\n",need_block_cnt);
	start_index = -1;
	for (i = 0; i < pool->block_cnt; i++) 
	{
		p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
		if (p_map_table->used) 
		{
			printf("before alloc: map index: %d is used\n", i);
			block_cnt = 0;
			start_index = -1;
			continue;
		}
 
		if (start_index == -1) 
		{
			start_index = i;
			//printf("start_index: %d\n", start_index);
		}
		block_cnt++;
 
		if (block_cnt == need_block_cnt) 
		{
			break;
		}
	}
 
	if (start_index == -1) 
	{
		printf("No available memory to used\n");
		return NULL;
	}
 
	alloc_table = alloc_talbe_pos(pool);
 
	for (i = 0; i < pool->block_cnt; i++) {
		p_alloc_table = (Memory_Alloc_Table *)((char *)alloc_table + i * sizeof(Memory_Alloc_Table));
		if (p_alloc_table->used == 0) {
			break;
		}
		p_alloc_table = NULL;
	}
 
	if (p_alloc_table == NULL) {
		return NULL;
	}
	p_map_table = (Memory_Map_Table *)((char *)map_table + sizeof(Memory_Map_Table) * start_index);
	p_alloc_table->p_start = p_map_table->p_block;
	p_alloc_table->block_start_index = start_index;//p_map_table->index;
	p_alloc_table->block_cnt = block_cnt;
	p_alloc_table->used = 1;
 
	//printf("block cnt is %d\n", block_cnt);
	for (i = start_index; i < start_index + block_cnt; i++) {
		p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
		//printf("map index: %d is used\n", i);
		p_map_table->used = 1;
	}
 
	printf("Alloc size: %d, Block: (start: %d, end: %d, cnt: %d)\n", size,
			start_index, start_index + block_cnt - 1, block_cnt);
	pool->alloc_cnt++;
	pool->used_size += size;
	return p_alloc_table->p_start;
}
 //将pool中memeory处的内存释放
void memory_free(Memory_Pool *pool, void *memory)
{
	Memory_Map_Table *map_table = NULL;
	Memory_Map_Table *p_map_table = NULL;
	Memory_Alloc_Table *alloc_table = NULL;
	Memory_Alloc_Table *p_alloc_table = NULL;
	int i = 0;
	int block_start_index = 0;
	int block_cnt = 0;
 
	if (memory == NULL) {
		printf("memory_free(): memory is NULL\n");
		return;
	}
 
	if (pool == NULL) {
		printf("Pool is NULL\n");
		return;
	}
 
	alloc_table = alloc_talbe_pos(pool);
 	printf("pool当前分配数量=%d  \n",pool->alloc_cnt);
	for (i = 0; i < pool->alloc_cnt; i++) //
	{
		p_alloc_table = (Memory_Alloc_Table *)((char *)(alloc_table) + i * sizeof(Memory_Alloc_Table));
		if (p_alloc_table->p_start == memory) 
		{
			block_start_index = p_alloc_table->block_start_index;
			block_cnt = p_alloc_table->block_cnt;
			p_alloc_table->used =0;
			pool->alloc_cnt --;
		}
		printf("s=%p \n",p_alloc_table->p_start);
	}
 
	if (block_cnt == 0) //遍历分配表,找不到
	{
		printf("error in [%s]:mem=%p,block_cnt = 0,free none!\n",__func__,memory);
		return;
	}
 
	map_table = map_table_pos(pool);
 
	printf("Block: free: start: %d, end: %d, cnt: %d\n", block_start_index,
			block_start_index + block_cnt -1, block_cnt);

	for (i = block_start_index; i < block_start_index + block_cnt; i++) 
	{
		p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
		p_map_table->used = 0;
	}
 
	p_alloc_table->used = 0;
	pool->used_size -= block_cnt * BLOCK_SIZE;
}
 
void memory_pool_destroy(Memory_Pool *pool)
{
	if (pool == NULL) {
		printf("memory_pool_destroy: pool is NULL\n");
		return;
	}
 
	free(pool);
	pool = NULL;
}
 
// main.c:
// #include <stdio.h>
 
// #include "memory_pool.h"
 
#if 0
#define LOOP 5
#define ALLOC_SIZE 8
 
int main(void)
{
	Memory_Pool *pool = NULL;
	char *p1 = NULL;
	char *p2 = NULL;
	int i = 0;
 
	
 
	pool = memory_pool_init(1024, 512);
	if (pool == NULL)
		printf("memory pool init failed\n");
 
	for (i = 0; i < 2; i++) 
    {
		p1 = (char *)Memory_malloc(pool, ALLOC_SIZE);
		if (p1 == NULL)
			printf("Malloc failed\n");
		else
			printf("Malloc success\n");
 
		// memory_free(pool, p1);
	}
 
 
	p1 = (char *)Memory_malloc(pool, 256);
	if (p1 == NULL)
		printf("Malloc failed\n");
	else
		printf("Malloc success\n");
 
	p2 = (char *)Memory_malloc(pool, 512);
	if (p1 == NULL)
		printf("Malloc failed\n");
	else
		printf("Malloc success\n");
 
	memory_free(pool, p1);
    
 
	p1 = (char *)Memory_malloc(pool, 256);
	if (p1 == NULL)
		printf("Malloc failed\n");
	else
		printf("Malloc success\n");
 
	memory_pool_destroy(pool);
 
	return 0;
}
#endif

 tab_queue.c

#include "tab_queue.h"
#include "mem_pool.h"
#define ALLOC_SIZE 16
#define CNT_MP 10//1000
#define MP_SIZE ( CNT_MP* ALLOC_SIZE)
static Memory_Pool *pool = NULL;
//队列的初始化
void InitQueue(LinkQueue *q)
{
    // q->front = (LinkQueue*)malloc(sizeof(QNode));
    
    pool = memory_pool_init(MP_SIZE,ALLOC_SIZE);//
    
    q->front = (QNode*)Memory_malloc(pool,sizeof(QNode));
    // printf("1===%ld",sizeof(QNode));
    if(!q->front)
    {
        printf("存储分配失败 !\n");
        return;
    }
    q->rear = q->front;
    q->front->next = NULL;
}
/* 求队列的长度 */
int QueueLength(LinkQueue Q)
{ 
	int i=0;
	QNode *p=Q.front;
	while(Q.rear!=p)
	{
		 i++;
		 p=p->next;
	}
	return i;
}
 //查找元素
void *FindElem(LinkQueue *Q, ElemType e)
{
	if (Q->front == Q->rear)
		return NULL;
    if((Q== NULL))     return 0;   
	QNode *p = Q->front->next;
    QNode *f =p;
    uint16_t i=0;
	while (p)
	{
		// if (p->data == e)
        if((p->data.time == e.time)&&(p->data.source_id == e.source_id)&&(p->data.obj_id == e.obj_id))
        {
            // return 1;//成功返回1
            return f;
        }
		else
		{
            f =p;
			p = p->next;
            i++;
		}
	}
	return NULL;//失败返回0
}
//队列的插入
void InsertQueue(LinkQueue *p,ElemType *e)
//队列为p,要插入的元素为e,队列的rear指针指向队列的最后一个元素。队列的front指针指向头结点,头结点无元素
{
    // QNode *ptr= (QNode*)malloc(sizeof(QNode));
    QNode *spf=p->front->next;
    QNode *ptr= (QNode *)Memory_malloc(pool,sizeof(QNode));
    ptr->next= NULL;
    printf("insert:%p;p->f=%p;",ptr,p->front->next);
    if(ptr ==NULL) /* 存储分配失败 */
    {
        printf("存储分配失败 in [%s] !\n",__func__);
        return ;
    }

    ptr->data = *e;;
    p->rear->next = ptr;
    p->rear = p->rear->next;
    p->rear = ptr;
    
    // p->front->next = spf;
    printf("spf=%p,p->f=%p, p->r=%p \n",spf,p->front->next,p->rear);
}
 
//队列的删除
void DeleteQueue(LinkQueue *p,ElemType *e)
{
    QNode *s;
    if(p->front == p->rear)
    {
        return;
    }
    s = p->front->next;
    *e = s->data;
    p->front->next = s->next;
    // p->front->next = p->front->next;
    //   if(s == p->rear)
    
    if(p->front->next == NULL)//用这条也可以是等价的
    {
        p->front = p->rear;
    }
    printf("del%p;p->f=%p, p->r=%p \n",s,p->front->next,p->rear);
    // memory_free(pool,(QNode *) &(e->time));
    memory_free(pool,s);
    // free(s);
}
 
//销毁一个队列
void DestoryQueue(LinkQueue *p)
{
    
    while(p->front)
    {
        p->rear = p->front->next;//p->front->next == NULL
        memory_free(pool, p->front);
        // free(p->front);//释放p的头结点
        p->front = p->rear;//把p的front和rear都置为NULL
    }
 
}
/* 从队头到队尾依次对队列Q中每个元素输出 */
int QueueTraverse(LinkQueue Q)
{
	QNode * p;
	p=Q.front->next;
    if(p == NULL)
        printf("null queue!\n");
	while(p)
	{
		//  visit(p->data);
         printf("%p:%d,%02x,%02x\n",p,p->data.time,p->data.source_id,p->data.obj_id);
		 p=p->next;
	}
	printf("\n");
	return 1;
}
#if 1
int main()
{
#if 0
    int i,len = 0;
    LinkQueue p;
    ElemType e={};
    char d,c;
    InitQueue(&p);
    printf("输入字符串:\n");
    scanf("%c",&d);
    while(c != '#')
    {
        InsertQueue(&p,&c);
        len++;
        scanf("%c",&c);
    }
    printf("len=%d\n",QueueLength(p));
    if(FindElem(&p,d) ==1)
        printf("get sucess!\n");
    printf("字符串为:\n");
    for(i = 1;i <= len;i++)
    {
        DeleteQueue(&p,&e);
        printf("%c",e);
    }
#else
    int i;
    LinkQueue p;
    ElemType *pe;
    ElemType ie;
    ElemType e;
    InitQueue(&p);
    for(i = 1;i <= 1;i++)
    {
        ie.time =i; 
        ie.source_id = i/2;
        ie.obj_id =i%5;
        InsertQueue(&p,&ie);
    }
    printf("len=%d\n",QueueLength(p));
    
    QueueTraverse(p);
    ie.time=3;ie.source_id=9;ie.obj_id=3;
    pe = (ElemType *)FindElem(&p,ie);
    printf("pp=%p\n",pe);
    if(pe)
    {
        printf("get sucess===!\n");
        printf("get1:%02x,%02x,%02x\n",pe->time,pe->source_id,pe->obj_id);
        DeleteQueue((LinkQueue *)&(pe),&e);
        QueueTraverse(p);
        printf("len=%d,",QueueLength(p));
        printf("del:%02x,%02x,%02x\n",e.time,e.source_id,e.obj_id);
    }    
    else
    {
        printf("get fail====!\n");
        ie.time=2;
        InsertQueue(&p,&ie);
    }
    // DeleteQueue(&p,&e);
    // QueueTraverse(p);
    // printf("len=%d\n",QueueLength(p));
    //     printf("del:%02x,%02x,%02x\n",e.time,e.source_id,e.obj_id);

    ie.time=2;
     printf("=============len=%d===========\n",QueueLength(p));
    int len ;
    while(1)
    {
        len = QueueLength(p);
        printf("len =%d \n",len);
        if(len>=(CNT_MP-1))
        {
            DeleteQueue(&(p),&e);
            // DeleteQueue(&(p),&ie);
        }
        QueueTraverse(p);    
        ie.time++;
        usleep(10*1000);
        InsertQueue(&p,&ie);
        
    }
    return 0;
    #endif
}
#endif

 Makefile文件,根据编译器--修改自己的编译cc

.SUFFIXES : .x .o .c .s

# CC := arm-linux-gcc
CC=     $(shell which gcc)
# STRIP := arm-linux-strip

#TARGET = tcp_demo
#SRCS := gpio_demo.c
#TARGET = crc
#SRCS := crc.c
# TARGET = tab_queue
# SRCS := tab_queue.c
TARGET = que_pool
SRCS := mem_pool.c \
		tab_queue.c
all: 
	$(CC) -static $(SRCS) -o $(TARGET) -g
# $(STRIP) $(TARGET) 
	
# cp -va $(TARGET) /nfsroot/
clean:
	rm -f *.o 
	rm -f *.x 
	rm -f *.flat
	rm -f *.map
	rm -f temp
	rm -f *.img
	rm -f $(TARGET)	
	rm -f *.gdb
	rm -f *.bak

测试结果:

参考博客:
基于Linux C内存池的实现(纯代码演示) - 知乎

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

单链表、内存池应用-消息抑制表的应用 的相关文章

  • 学生成绩管理系统-python

    乱写的成绩管理系统 派森 span class token comment 定义学生类型 姓名 学号 科目 span span class token keyword class span span class token class na
  • 11_3、Java集合之迭代器Iterator接口

    一 引入 Iterator对象称为迭代器 设计模式的一种 xff0c 主要用于遍历 Collection 集合中的元素 GOF给迭代器模式的定义为 xff1a 提供一种方法访问一个容器 container 对象中各个元 素 xff0c 而又
  • 进程切换和进程调度的区别

    进程切换和进程调度的区别 调度是决定将系统资源分配给哪个进程 xff0c 进程切换是实际分配系统资源 另外需要注意进程切换一定会产生中断 xff0c 进行处理器模式切换 xff0c 即从用户态进入内核态 xff0c 之后又回到用户态 xff
  • 树莓派3b+安装ubuntu server,安装mysql

    1 下载镜像 http cdimage ubuntu com ubuntu releases 18 04 5 release ubuntu 18 04 5 preinstalled server arm64 43 raspi3 img xz
  • 【GVINS初体验】

    在Ubuntu18 04下跑通GVINS GVINS介绍 环境配置 1 C 11编译器 2 ROS 3 Eigen 4 Ceres 5 gnss comm Build GVINS 跑VINS啦 GVINS介绍 GVINS是一个基于非线性优化
  • 【OpenCV】基于Adaboost和Haar-like特征人脸识别

    毕设算是告一段落 xff0c 里面用了一点点人脸识别 xff0c 其实完全是OpenCV自带的 xff0c 源自两篇论文 xff1a P Viola and M Jones Rapid object detection using a bo
  • Jetson Tx2上跑MYNT_EYE的ORB SLAM示例

    愁呀 xff0c 按照官网的说明文档 xff0c 好长时间郁闷在跑不起来 每次都是在加载词袋时报bad malloc 打开MYNT EYE ORB SLAM2 Sample Vocabulary ORBvoc txt词袋看见1082073行
  • 解决ST-LINK无法连接设备(解决不了你顺着网线来打我)

    问题分析 问题描述 在mdk中 xff0c 点击下载按钮提示找不到目标设备 xff0c 无法自动下载程序 原因猜想 单片机只有在停止状态下才可以下载程序 xff1f 猜想验证 如果让单片机处在停止状态 xff0c 是不是就能正常下载了呢 x
  • tensorflow 利用tfrecords文件制作数据集

    TensorFlow之tfrecords文件详细教程 制作数据集思路 xff1a 将训练数据和测试数据生成tfrecords文件 为什么呢 xff1f 这种文件以二进制进行存储 xff0c 只占用一个内存块 对于大数据能够提高cpu效率 代
  • 解决mininet运行报错“ImportError: No module named mininet.log”

    解决mininet运行报错 ImportError No module named mininet log 运行环境 系统Ubuntu 04 安装Mininet 2 3 0d6问题描述 运行miniedit py时报错ImportError
  • C++ 用结构体和类创建单向链表

    一 结构体 include lt iostream gt using namespace std 一个链表要实现的操作有 建立链表 xff0c 遍历链表 xff0c 查找链表 xff0c 插入和删除节点 查找和遍历某种程度上来说是一样的 x
  • 巨星星座paper研究

    巨星星座paper研究 ICM1篇 Exploring the Internet from space with Hypatia Hypatia论文 xff1a 摘要 xff1a Hypatia 提出了一个框架 xff0c 通过结合这些星座
  • Ubuntu20.04中安装ns3网络仿真器

    前言 我的环境 Ubuntu 20 04 xff0c 安装的是ns3 3 33 1 安装前的准备工作 建议先了解一下ns3的文件结构 参考博客 xff1a https blog csdn net sinat 36418396 article
  • ubuntu 20.04配置ssh远程root连接

    ubuntu 20 04配置ssh远程服务 1 开启服务 etc init d ssh start 查看ssh服务状态 sudo service ssh status 正常是active xff08 running xff09 2 修改ss
  • docker 遇到的问题

    docker stop container id 失败 显示 root 64 docker stop onos1 Error response from daemon cannot stop container onos1 permissi
  • docker ubuntu20.04 dockerfile 换源

    dockerfile 换源 FROM ubuntu 20 04 ARG span class token assign left variable DEBIAN FRONTEND span span class token operator
  • Prometheus普罗米修斯-入门

    Promethus 普罗米修斯 xff09 适合k8s和docker的监控系统 功能 能够安装prometheus服务器 能够通过安装node exporter监控远程linux 能够通过安装mysqld exporter监控远程mysql
  • 数据库操作

    ubt1804 安装mqsql span class token function apt span span class token function install span mysql server span class token
  • 图的邻接表存储及图的遍历(DFS)

    图的表示方式 邻接矩阵 xff1a G N N xff0c 适合稠密图 xff0c 占用空间大 xff0c O N N 邻接表 xff1a 存储稀疏有向图 xff0c 避免空间浪费十字链表 xff1a 针对有向图 xff0c 把邻接表和逆邻
  • HTML5详细介绍及使用

    HTML5详细介绍及使用 一 HTML5简介 1 HMTL5的定义 HTML是一种用符号来创建结构文档的语义 比如标题 章节 列表 链接 引用和其他各种元素都可以包含在结构文档中 HTML5在W3C中的定义 xff1a HTML 5 是下一

随机推荐