C語言實現的位元組陣列緩衝區(執行緒安全) --- 親測OK
阿新 • • 發佈:2020-08-01
基於單向連結串列實現動態資料緩衝區 ---- 類似java的StringBuffer
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; // 通過摘掉節點 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.\n"); 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 void *XXXX_mutex_init( void ); 16 void XXXX_mutex_take( void *mutex ); 17 void XXXX_mutex_give( void *mutex ); 18 19 #define XXXX_malloc malloc 20 #define XXXX_free free 21 #define XXXX_print_ln_E(fmt, arg...) { printf(fmt"\r\n", ##arg); } 22 #define XXXX_print_ln_I(fmt, arg...) { printf(fmt"\r\n", ##arg); } 23 24 // 輸入引數標識 25 #define IN 26 27 // 輸出引數標識 28 #define OUT 29 30 // 輸入輸出引數標識 31 #define INOUT 32 33 typedef struct node_data 34 { 35 unsigned int len_used; // 節點資料已使用長度 36 unsigned int len_data; // 節點資料長度 37 unsigned char *data; // 節點資料指定為整型 38 }Node_data_t; 39 40 /* 封裝連結串列節點 */ 41 typedef struct node 42 { 43 Node_data_t data; // 節點資料 44 struct node *next; // 下一個節點 45 } Node_t; 46 47 /* 封裝連結串列頭節點 */ 48 typedef struct _node_head 49 { 50 Node_data_t data; // 節點資料 51 struct node *next; // 下一個節點 52 void *lock; // 鎖 53 } Node_head_t; 54 55 /** 56 * @函式名: XXXX_SINGLELIST_append_tail 57 * @函式功能: 插入節點到連結串列尾 58 * @引數: h:連結串列頭結點的地址 data:待插入的資料 59 * @返回值:插入成功返回0,失敗返回非零 60 */ 61 int XXXX_SINGLELIST_append_tail(IN Node_head_t *h, IN Node_data_t *node_data); 62 63 /** 64 * @函式名: XXXX_SINGLELIST_print 65 * @函式功能: 遍歷連結串列所有資料 66 * @引數: h:連結串列頭結點的地址 67 * @返回值: void 68 */ 69 void XXXX_SINGLELIST_print(IN const Node_head_t *h); 70 71 /** 72 * @函式名: XXXX_SINGLELIST_delete 73 * @函式功能: 在連結串列中刪除指定值的節點,如果有多個匹配則刪除全部 74 * @引數: h:連結串列頭結點的地址 data:待刪除的資料 75 * @返回值: void 76 */ 77 void XXXX_SINGLELIST_delete(IN Node_head_t *h); 78 79 void *BytesBuffer_create(void); 80 void BytesBuffer_delete(IN void *p_head); 81 int BytesBuffer_read(IN void *p_head, OUT unsigned char *out_buf, IN unsigned int expected_read_len); 82 int BytesBuffer_append(IN void *p_head, IN unsigned char *in_buf, IN unsigned int expected_append_len); 83 84 #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\n"); 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("\t\tr_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 }
1 gcc *.c -o a.out -Wall -lpthread -g ; ./a.out