参考:https://blog.csdn.net/aiwangtingyun/article/details/79705042
参考:https://baike.baidu.com/item/realloc/659993?fr=aladdin
C语言,基于单向链表实现,变长动态数据缓冲区(线程安全) ---- 类似java的StringBuffer
0、我的实现与realloc、环形数组的区别
0.1 realloc原理
-
如果有足够空间用于扩大mem_address指向的内存块,则分配额外内存,并返回mem_address。这里说的是“扩大”,我们知道,realloc是从堆上分配内存的,当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平。也就是说,如果原先的内存大小后面还有足够的空闲空间用来分配,加上原来的空间大小= newsize。那么就ok。得到的是一块连续的内存。
-
如果原先的内存大小后面没有足够的空闲空间用来分配,那么从堆中另外找一块newsize大小的内存。并把原来大小内存空间中的内容复制到newsize中。返回新的mem_address指针。(数据被移动了)。老块被放回堆上。
0.2 我的原理
我的是一个buffer,不能像realloc那样可扩大、可缩小,我的只能扩大,类似于流的缓存
原理是:
数据追加——不再顾虑原来分配的空间,而是重新分配出要扩大的空间,将指令以节点方式挂在单向表的尾部
数据读取——从头节点中读出数据,如果头节点被读完,则删除并释放头节点对应的内存
0.3 要不要使用我的方式
如果你的内存够用,大可不必像我这样实现,直接调用realloc即可
有的同学说使用环形数组,环形数组是定长的缓冲区,并且数据接收是可控的范围时使用。
如果你的内存很紧缺,或者接收的数据不可控——另一个模块在不断的塞给你数据,你又不得不接,环形数组分配太大浪费内存,分配太小不够用,给的数据不存就丢了,这种场景可以以用我的方式,内存用多少开多少,随时用随时申请,请往下看。
1、就4个接口:
1 void *BytesBuffer_create(void); // 缓冲区句柄创建 2 void BytesBuffer_delete(IN void *p_head); // 缓冲区销毁 3 int BytesBuffer_read(IN void *p_head, OUT unsigned char *out_buf, IN unsigned int expected_read_len); // 缓冲区读 4 int BytesBuffer_append(IN void *p_head, IN unsigned char *in_buf, IN unsigned int expected_append_len); // 缓冲区写
2、直接上代码,两个缓冲区文件,一个测试文件
1 /** 2 * Copyright © XXXX Technologies Co., Ltd. All Rights Reserved. 3 * @Date 2020年08月01日,下午16:00:00 4 */ 5 6 /********************************************************************************************** 7 * 文件描述: 该文件为带头结点的单链表库函数中,部分功能函数的实现 8 * 日期: 2020.08.01 16:00:00 9 * 作者: LiuYan 10 **********************************************************************************************/ 11 12 #include <stdlib.h> 13 #include <stdio.h> 14 #include <string.h> 15 16 #include "single_linked_list.h" 17 18 /********************************************************************************************** 19 单向链表 : 遍历打印链表所有数据 20 21 22 日期: 2020.08.01 16:00:00 23 作者: LiuYan 24 25 参数: h:链表头结点的地址 26 27 返回值: 无 28 29 **********************************************************************************************/ 30 void XXXX_SINGLELIST_print(IN const Node_head_t *h) 31 { 32 Node_t *i = NULL; 33 int index = 0; 34 35 /* 检查是否为空链表 */ 36 if (NULL == h || NULL == h->next) 37 { 38 XXXX_print_ln_E("Empty list."); 39 return; 40 } 41 42 /* 遍历链表 */ 43 for (index = 0, i = h->next; i != NULL; index++, i = i->next) 44 { 45 XXXX_print_ln_I("[%d]= %d/%d:%p", index, i->data.len_used, i->data.len_data, i->data.data); 46 } 47 } 48 49 /********************************************************************************************** 50 单向链表 : 删除链表头节点后的第一个节点 51 52 53 日期: 2020.08.01 16:00:00 54 作者: LiuYan 55 56 参数: h:链表头结点的地址 57 58 返回值: 成功返回0, 空链表返回-1 59 60 **********************************************************************************************/ 61 int XXXX_SINGLELIST_delete_first(IN Node_head_t *h) 62 { 63 Node_t *fast = NULL; // 快指针 64 65 // 获取锁 66 if (NULL != h->lock) { 67 XXXX_mutex_take(h->lock); 68 } 69 70 /* 检查是否为空链表 */ 71 if (NULL == h || NULL == h->next) 72 { 73 XXXX_print_ln_E("Empty list."); 74 // 释放锁 75 if (NULL != h->lock) { 76 XXXX_mutex_give(h->lock); 77 } 78 79 return -1; 80 } 81 82 fast = h->next; // 快指针 83 84 h->next = fast->next; // 通过摘掉节点
fast->next = NULL;
fast->data.len_used = 0;
fast->data.len_data = 0;
if (NULL != fast->data.data) {
FEITIAN_00_free(fast->data.data);
fast->data.data = NULL;
}
85 XXXX_free(fast); // 和释放节点空间达到删除目的 86 fast = NULL; 87 88 // 释放锁 89 if (NULL != h->lock) { 90 XXXX_mutex_give(h->lock); 91 } 92 93 return 0; 94 } 95 96 /********************************************************************************************** 97 单向链表 : 删除链表的所有节点(除了头节点) 98 99 100 日期: 2020.08.01 16:00:00 101 作者: LiuYan 102 103 参数: h:链表头结点的地址 104 105 返回值: 无 106 107 **********************************************************************************************/ 108 void XXXX_SINGLELIST_delete(IN Node_head_t *h) 109 { 110 int ret = 0; 111 112 /* 检查是否为空链表 */ 113 if (NULL == h || NULL == h->next) 114 { 115 XXXX_print_ln_E("Empty list."); 116 return; 117 } 118 119 /* 遍历链表 */ 120 for (; 0 == ret; ) 121 { 122 ret = XXXX_SINGLELIST_delete_first(h); 123 } 124 } 125 126 /********************************************************************************************** 127 单向链表 : 创建一个节点 128 129 130 日期: 2020.08.01 16:00:00 131 作者: LiuYan 132 133 参数: 无 134 135 返回值: 成功返回新节点指针,失败返回NULL 136 137 **********************************************************************************************/ 138 Node_t *XXXX_SINGLELIST_create_node(void) 139 { 140 Node_t *newNode = NULL; 141 142 /* 第一步:分配新节点空间 */ 143 newNode = XXXX_malloc(sizeof(Node_t)); 144 if (NULL == newNode) 145 { 146 XXXX_print_ln_E("malloc Failed(size=%u).", (unsigned int)sizeof(Node_t)); 147 return NULL; 148 } 149 150 memset((void *)newNode, 0, sizeof(Node_t)); 151 152 return newNode; 153 } 154 155 /********************************************************************************************** 156 单向链表 : 插入节点到链表尾 157 158 **** 注意: 调用完毕此函数后, 请自行维护 node_data 对应的实参 *** 159 160 日期: 2020.08.01 16:00:00 161 作者: LiuYan 162 163 参数: h:链表头结点的地址, node_data:待插入的节点 164 165 返回值: 成功返回0,失败返回-1 166 167 **********************************************************************************************/ 168 169 int XXXX_SINGLELIST_append_tail(IN Node_head_t *h, IN Node_data_t *node_data) 170 { 171 Node_t *newNode = NULL; 172 Node_t *i = (Node_t *)h; 173 174 // 获取锁 175 if (NULL != h->lock) { 176 XXXX_mutex_take(h->lock); 177 } 178 179 /* 参数检查 */ 180 if (NULL == h || NULL == node_data) 181 { 182 XXXX_print_ln_E("wrong para1."); 183 184 // 释放锁 185 if (NULL != h->lock) { 186 XXXX_mutex_give(h->lock); 187 } 188 return -1; 189 } 190 191 /* 第一步:分配新节点空间 */ 192 newNode = XXXX_SINGLELIST_create_node(); 193 if (NULL == newNode) 194 { 195 XXXX_print_ln_E("create_node Failed."); 196 197 // 释放锁 198 if (NULL != h->lock) { 199 XXXX_mutex_give(h->lock); 200 } 201 return -1; 202 } 203 204 /* 第二步:赋值给新节点 */ 205 memcpy((void *)&newNode->data, (void *)node_data, sizeof(Node_data_t)); 206 207 /* 第三步:找到链表尾 */ 208 while (i->next != NULL) 209 { 210 i = i->next; 211 } 212 213 /* 第四步:把新节点插入到链表尾 */ 214 i->next = newNode; // 尾节点指向新节点 215 newNode->next = NULL; // 新节点指向NULL,作为链表尾 216 217 // 释放锁 218 if (NULL != h->lock) { 219 XXXX_mutex_give(h->lock); 220 } 221 222 return 0; // 成功返回0 223 } 224 225 /********************************************************************************************** 226 字节缓存区 : 创建对象 227 228 229 日期: 2020.08.01 16:00:00 230 作者: LiuYan 231 232 参数: 无 233 234 返回值: NULL: 失败 235 非NULL: 成功, 返回对象 236 237 **********************************************************************************************/ 238 void *BytesBuffer_create(void) 239 { 240 Node_head_t *headNode = NULL; 241 242 /* 第一步:分配新节点空间 */ 243 headNode = XXXX_malloc(sizeof(Node_head_t)); 244 if (NULL == headNode) 245 { 246 XXXX_print_ln_E("malloc Failed(size=%u).", (unsigned int)sizeof(Node_head_t)); 247 return NULL; 248 } 249 250 memset((void *)headNode, 0, sizeof(Node_head_t)); 251 252 headNode->lock = XXXX_mutex_init(); 253 if ( NULL == headNode->lock ) { 254 XXXX_print_ln_E(" mutex create failed. "); 255 } 256 257 return (void *)headNode; 258 } 259 260 /********************************************************************************************** 261 字节缓存区 : 销毁对象 262 263 264 日期: 2020.08.01 16:00:00 265 作者: LiuYan 266 267 参数: p_head, 待销毁对象 268 269 返回值: 无 270 271 **********************************************************************************************/ 272 void BytesBuffer_delete(IN void *p_head) 273 { 274 Node_head_t *h = (Node_head_t *)p_head; 275 276 /* 检查是否为空链表 */ 277 if (NULL == h || NULL == h->next) 278 { 279 XXXX_print_ln_E("Empty list."); 280 return; 281 } 282 283 XXXX_SINGLELIST_delete((Node_head_t *)p_head); 284 285 XXXX_free(p_head); 286 p_head = NULL; 287 } 288 289 /********************************************************************************************** 290 字节缓存区 : 读取 291 292 293 日期: 2020.08.01 16:00:00 294 作者: LiuYan 295 296 参数: p_head, 字节缓存区对象 297 out_buf, 字节输出 298 expected_read_len, 期望读取字节个数 299 300 返回值: >=0: 成功读取字节个数 301 302 **********************************************************************************************/ 303 int BytesBuffer_read(IN void *p_head, OUT unsigned char *out_buf, IN unsigned int expected_read_len) 304 { 305 Node_t *i = NULL; 306 unsigned int curr_copy_len = 0; 307 unsigned int curr_node_bytes = 0; 308 unsigned int already_copy_len = 0; 309 unsigned int left_copy_len = expected_read_len; 310 Node_head_t *h = (Node_head_t *)p_head; 311 312 /* 检查是否为空链表 */ 313 if (NULL == h || NULL == h->next || NULL == out_buf || 0 == expected_read_len) 314 { 315 XXXX_print_ln_E("Empty list."); 316 return 0; 317 } 318 319 /* 遍历链表 */ 320 for (i = h->next; i != NULL; ) 321 { 322 if (i->data.len_data <= i->data.len_used) 323 { 324 i = i->next; // 即将删除i节点, 准备好下一点节指令 325 XXXX_SINGLELIST_delete_first(h); 326 continue; 327 } 328 329 left_copy_len = expected_read_len - already_copy_len; 330 331 curr_node_bytes = (i->data.len_data - i->data.len_used); 332 curr_copy_len = (curr_node_bytes > left_copy_len) ? left_copy_len : curr_node_bytes; 333 334 memcpy((void *)(out_buf + already_copy_len), i->data.data + i->data.len_used, curr_copy_len); 335 336 i->data.len_used += curr_copy_len; 337 if (i->data.len_data <= i->data.len_used) 338 { 339 i = i->next; // 即将删除i节点, 准备好下一点节指令 340 XXXX_SINGLELIST_delete_first(h); 341 } 342 343 already_copy_len += curr_copy_len; 344 345 if (already_copy_len >= expected_read_len) { 346 break; 347 } 348 349 } 350 351 return already_copy_len; 352 } 353 354 /********************************************************************************************** 355 字节缓存区 : 追加 356 357 358 **** 注意: 调用完毕此函数后, 调用者请不要释放 in_buf 对应的缓冲区 *** 359 360 日期: 2020.08.01 16:00:00 361 作者: LiuYan 362 363 参数: p_head, 字节缓存区对象 364 in_buf, 待追加的字节流, 调用者请在堆中分配 365 expected_append_len, 待追加的字节流字节个数 366 367 返回值: 成功返回0,失败返回-1 368 369 **********************************************************************************************/ 370 int BytesBuffer_append(IN void *p_head, IN unsigned char *in_buf, IN unsigned int expected_append_len) 371 { 372 Node_data_t node_data; 373 Node_head_t *h = (Node_head_t *)p_head; 374 int ret = -1; 375 376 /* 参数检查 */ 377 if (NULL == h || NULL == in_buf || 0 == expected_append_len) 378 { 379 XXXX_print_ln_E("wrong para."); 380 return -1; 381 } 382 383 memset((void *)&node_data, 0, sizeof(Node_data_t)); 384 385 node_data.len_used = 0; 386 node_data.len_data = expected_append_len; 387 node_data.data = in_buf; 388 389 390 ret = XXXX_SINGLELIST_append_tail(h, &node_data); 391 392 memset((void *)&node_data, 0, sizeof(Node_data_t)); 393 394 return ret; 395 }
1 /** 2 * Copyright © XXXX Technologies Co., Ltd. All Rights Reserved. 3 * @Date 2020年08月01日,下午16:00:00 4 */ 5 6 /********************************************************************************************** 7 * 文件描述: 该文件为带头结点的单链表库函数中,部分功能函数的实现 8 * 日期: 2020.08.01 16:00:00 9 * 作者: LiuYan 10 **********************************************************************************************/ 11 12 #ifndef _NODELIST_H_ 13 #define _NODELIST_H_ 14 15 typedef struct node_data 16 { 17 unsigned int len_used; // 节点数据已使用长度 18 unsigned int len_data; // 节点数据长度 19 unsigned char *data; // 节点数据指定为整型 20 }Node_data_t; 21 22 /* 封装链表节点 */ 23 typedef struct node 24 { 25 Node_data_t data; // 节点数据 26 struct node *next; // 下一个节点 27 } Node_t; 28 29 /* 封装链表头节点 */ 30 typedef struct _node_head 31 { 32 Node_data_t data; // 节点数据 33 struct node *next; // 下一个节点 34 void *lock; // 锁 35 } Node_head_t; 36 37 /** 38 * @函数名: XXXX_SINGLELIST_append_tail 39 * @函数功能: 插入节点到链表尾 40 * @参数: h:链表头结点的地址 data:待插入的数据 41 * @返回值:插入成功返回0,失败返回非零 42 */ 43 int XXXX_SINGLELIST_append_tail(IN Node_head_t *h, IN Node_data_t *node_data); 44 45 /** 46 * @函数名: XXXX_SINGLELIST_print 47 * @函数功能: 遍历链表所有数据 48 * @参数: h:链表头结点的地址 49 * @返回值: void 50 */ 51 void XXXX_SINGLELIST_print(IN const Node_head_t *h); 52 53 /** 54 * @函数名: XXXX_SINGLELIST_delete 55 * @函数功能: 在链表中删除指定值的节点,如果有多个匹配则删除全部 56 * @参数: h:链表头结点的地址 data:待删除的数据 57 * @返回值: void 58 */ 59 void XXXX_SINGLELIST_delete(IN Node_head_t *h); 60 61 void *BytesBuffer_create(void); 62 void BytesBuffer_delete(IN void *p_head); 63 int BytesBuffer_read(IN void *p_head, OUT unsigned char *out_buf, IN unsigned int expected_read_len); 64 int BytesBuffer_append(IN void *p_head, IN unsigned char *in_buf, IN unsigned int expected_append_len); 65 66 #endif //_NODELIST_H
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pthread.h> 4 #include <string.h> 5 #include <sys/types.h> 6 #include <unistd.h> 7 #include "single_linked_list.h" 8 9 #include <fcntl.h> 10 11 12 /********************************************************************************************** 13 锁初始化 14 15 16 日期: 2019.09.20 10:36:00 17 作者: LiuYan 18 19 参数: 无 20 21 返回值: 锁指针 22 23 **********************************************************************************************/ 24 void *XXXX_mutex_init( void ) 25 { 26 static pthread_mutex_t g_mutex_lock; 27 int ret = 0; 28 29 ret = pthread_mutex_init(&g_mutex_lock, NULL); 30 if (ret != 0) { 31 XXXX_print_ln_E("mutex init failed "); 32 return NULL; 33 } 34 35 return (void *)&g_mutex_lock; 36 } 37 38 /********************************************************************************************** 39 锁获取 40 41 42 日期: 2019.09.20 10:36:00 43 作者: LiuYan 44 45 参数: mutex, 锁指针 46 47 返回值: 无 48 49 **********************************************************************************************/ 50 void XXXX_mutex_take( void *mutex ) 51 { 52 pthread_mutex_lock(mutex); 53 54 return; 55 } 56 57 /********************************************************************************************** 58 锁释放 59 60 61 日期: 2019.09.20 10:36:00 62 作者: LiuYan 63 64 参数: mutex, 锁指针 65 66 返回值: 无 67 68 **********************************************************************************************/ 69 void XXXX_mutex_give( void *mutex ) 70 { 71 pthread_mutex_unlock(mutex); 72 return; 73 } 74 75 unsigned char rand_byte() 76 { 77 // return rand() % 26 + 0x41; 78 return rand() % 0xff; 79 } 80 81 int rand_bytes(unsigned char **p_in_buf, int *p_rand_len) 82 { 83 int index = 0; 84 int rand_len = 0; 85 unsigned char *p = NULL; 86 87 rand_len = rand() % 1024 + 1; 88 p = XXXX_malloc(rand_len + 1); 89 if (NULL == p) 90 { 91 return -1; 92 } 93 94 memset((void *)p, 0, rand_len + 1); 95 96 for (index = 0; index < rand_len; index++) { 97 p[index] = rand_byte(); 98 } 99 100 *p_in_buf = p; 101 *p_rand_len = rand_len; 102 return 0; 103 } 104 105 void *bb = NULL; 106 107 #define char_file (0) 108 109 void *thr_fn(void *arg) 110 { 111 int ret = 0; 112 int rand_len = 0; 113 unsigned char *out_buf = NULL; 114 115 #if char_file 116 FILE * fp_r; 117 fp_r = fopen ("file_r.txt", "w+"); 118 #else 119 120 int fp_r = open("./file_r.txt", O_RDWR|O_CREAT); 121 XXXX_print_ln_I("fp_r=%d%s", fp_r, "./file_r.txt"); 122 123 #endif 124 125 for (; ;) 126 { 127 if (NULL == bb) { 128 usleep(1000 * 200); 129 continue; 130 } 131 132 rand_len = rand() % 1024 + 1; 133 out_buf = XXXX_malloc(rand_len + 1); 134 if (NULL == out_buf) 135 { 136 return ((void *)0); 137 } 138 139 memset((void *)out_buf, 0, rand_len + 1); 140 141 ret = BytesBuffer_read(bb, out_buf, rand_len); 142 // XXXX_print_ln_I(" r_ret=%d/%d:%s", ret, rand_len, out_buf); 143 144 #if char_file 145 fprintf(fp_r, "%s", out_buf); 146 #else 147 if (0 < ret) { 148 write(fp_r, out_buf, ret); 149 } 150 #endif 151 XXXX_free(out_buf); 152 153 // usleep(1000 * 50); 154 155 } 156 157 #if char_file 158 fclose(fp_r); 159 #else 160 close(fp_r); 161 #endif 162 163 return ((void *)0); 164 } 165 166 167 int main(int argc, char *argv[]) 168 { 169 int ret = 0; 170 unsigned char *in_buf = NULL; 171 int rand_len = 0; 172 pthread_t ntid; 173 int err = 0; 174 175 bb = BytesBuffer_create(); 176 if (NULL == bb) { 177 XXXX_print_ln_I("BytesBuffer_create Failed."); 178 return -1; 179 } 180 181 err = pthread_create(&ntid, NULL, thr_fn, NULL); 182 if(err != 0){ 183 XXXX_print_ln_I("can't create thread: %s",strerror(err)); 184 } 185 #if char_file 186 FILE * fp_w; 187 fp_w = fopen ("file_w.txt", "w+"); 188 #else 189 int fp_w = open("./file_w.txt", O_RDWR|O_CREAT); 190 XXXX_print_ln_I("fp_w=%d%s", fp_w, "./file_w.txt"); 191 #endif 192 193 194 for (; ;) 195 { 196 ret = rand_bytes(&in_buf, &rand_len); 197 if (0 != ret) { 198 return -1; 199 } 200 201 ret = BytesBuffer_append(bb, in_buf, rand_len); 202 203 //XXXX_print_ln_I("w_ret=%d/%d:%s", ret, rand_len, in_buf); 204 #if char_file 205 fprintf(fp_w, "%s", in_buf); 206 #else 207 write(fp_w, in_buf, rand_len); 208 #endif 209 210 // XXXX_free(in_buf); 不要释放 211 212 // XXXX_SINGLELIST_print((const Node_head_t *)bb); 213 214 // usleep(1000 * 50); 215 216 } 217 218 #if char_file 219 fclose(fp_w); 220 #else 221 close(fp_w); 222 #endif 223 224 return 0; 225 }
// 移植请实现以下接口 或 宏 #if 1 void *XXXX_mutex_init( void ); void XXXX_mutex_take( void *mutex ); void XXXX_mutex_give( void *mutex ); #define XXXX_malloc malloc #define XXXX_free free #define XXXX_print_ln_E(fmt, arg...) { printf(fmt" ", ##arg); } #define XXXX_print_ln_I(fmt, arg...) { printf(fmt" ", ##arg); } // 输入参数标识 #define IN // 输出参数标识 #define OUT // 输入输出参数标识 #define INOUT #endif
1 gcc *.c -o a.out -Wall -lpthread -g ; ./a.out