1. 程式人生 > 實用技巧 >C語言實現的位元組陣列緩衝區(執行緒安全) --- 親測OK

C語言實現的位元組陣列緩衝區(執行緒安全) --- 親測OK

基於單向連結串列實現動態資料緩衝區 ---- 類似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