## 說碼解扣-- QUEUE ### 1. 內容 - 簡介 - 可以把佇列想像成有分出入口的選舉投票室,投票者必須遵守「從入口進入」與「從出口離開」的動線,先進入投票者會先完成投票離開,將此對應到佇列結構,其入口為佇列的尾端,出口為佇列的前端,投票者則為資料。 - 特色 - 先進先出(First In First Out,FIFO) - 線性結構 - 頭、尾端有索引值(front,rear) - 功能 - Enqueue(data):從佇列尾端存入資料 - Dequeue():從佇列前端移除資料 - getFirst():回傳佇列前端(第一筆)的資料 - getLast():回傳佇列尾端(最後一筆)的資料 - getSize():回傳佇列目前的大小 - isEmpty():檢查佇列是否為空 - 應用 - CPU的工作排程 - 印表機的工作排序 - 網路伺服器傳輸 ### 2. 程式碼解說 :::spoiler queue_internal.h ```c== #ifndef __QUEUE_INTERNAL_H__ #define __QUEUE_INTERNAL_H__ #include <stdio.h> #include <stdlib.h> #include <queue.h> int8_t queue_lock_internal(queue_t *q); int8_t queue_unlock_internal(queue_t *q); int8_t queue_put_internal(queue_t *q, void *el, int (*action)(pthread_cond_t *, pthread_mutex_t *)); int8_t queue_get_internal(queue_t *q, void **e, int (*action)(pthread_cond_t *, pthread_mutex_t *), int (*cmp)(void *, void *), void *cmpel); int8_t queue_destroy_internal(queue_t *q, uint8_t fd, void (*ff)(void *)); ction to release the memory, NULL => free() int8_t queue_flush_internal(queue_t *q, uint8_t fd, void (*ff)(void *)); #endif /* __QUEUE_INTERNAL_H__ */ ``` ::: :::spoiler queue.h ```c== #ifndef __QUEUE_H__ #define __QUEUE_H__ #include <stdio.h> #include <stdlib.h> #include <stdint.h> /* (u)intX_t */ #ifndef _WIN32 #include <unistd.h> /* usleep */ #else #include <windows.h> /* Sleep */ #endif #include <errno.h> /* EBUSY */ #include <pthread.h> /* pthread_mutex_t, pthread_cond_t */ #ifdef _WIN32 #define sleepmilli(x) Sleep(x) #else #define sleepmilli(x) usleep(x * 1000) #endif #ifndef UINTX_MAX typedef uint16_t uintX_t; #define UINTX_MAX UINT16_MAX #endif #define DEFINE_Q_DESTROY(fname, type) int8_t fname(queue_t *q, void (*ff)(type *)) { return queue_destroy_complete(q, (void (*)(void *))ff); } #define DEFINE_Q_FLUSH(fname, type) int8_t fname(queue_t *q, void (*ff)(type *)) { return queue_flush_complete(q, (void (*)(void *))ff); } #define DEFINE_Q_GET(fname, type) int8_t fname(queue_t *q, type **e) { return queue_get(q, (void **)e); } #define DEFINE_Q_GET_WAIT(fname, type) int8_t fname(queue_t *q, type **e) { return queue_get_wait(q, (void **)e); } #define DEFINE_Q_PUT(fname, type) int8_t fname(queue_t *q, type *e) { return queue_put(q, (void *)e); } #define DEFINE_Q_PUT_WAIT(fname, type) int8_t fname(queue_t *q, type *e) { return queue_put_wait(q, (void *)e); } #define DEFINE_Q_FLUSH_PUT(fname, type) int8_t fname(queue_t *q, void (*ff)(type *), type *e) { return queue_flush_complete_put(q, (void (*)(void *))ff, (void *)e); } typedef enum queue_erros_e { Q_OK = 0, Q_ERR_INVALID = -1, Q_ERR_LOCK = -2, Q_ERR_MEM = -3, Q_ERR_NONEWDATA = -4, Q_ERR_INVALID_ELEMENT = -5, Q_ERR_INVALID_CB = -6, Q_ERR_NUM_ELEMENTS = -7 } queue_errors_t; typedef struct queue_element_s { void *data; struct queue_element_s *next; } queue_element_t; typedef struct queue_s { queue_element_t *first_el, *last_el; // (max.) number of elements uintX_t num_els; uintX_t max_els; // no new data allowed uint8_t new_data; // sorted queue int8_t sort; int8_t asc_order; int (*cmp_el)(void *, void *); // multithreaded pthread_mutex_t *mutex; pthread_cond_t *cond_get; pthread_cond_t *cond_put; } queue_t; /** * initializes and allocates a queue with unlimited elements * * returns NULL on error, or a pointer to the queue */ queue_t *queue_create(void); queue_t *queue_create_limited(uintX_t max_elements); queue_t *queue_create_sorted(int8_t asc, int (*cmp)(void *, void *)); queue_t *queue_create_limited_sorted(uintX_t max_elements, int8_t asc, int (*cmp)(void *, void *)); int8_t queue_destroy(queue_t *q); int8_t queue_destroy_complete(queue_t *q, void (*ff)(void *)); int8_t queue_flush(queue_t *q); int8_t queue_flush_complete(queue_t *q, void (*ff)(void *)); int8_t queue_flush_put(queue_t *q, void (*ff)(void *), void *e); int8_t queue_flush_complete_put(queue_t *q, void (*ff)(void *), void *e); uintX_t queue_elements(queue_t *q); int8_t queue_empty(queue_t *q); int8_t queue_put(queue_t *q, void *e); int8_t queue_put_wait(queue_t *q, void *e); int8_t queue_get(queue_t *q, void **e); int8_t queue_get_wait(queue_t *q, void **e); int8_t queue_get_filtered(queue_t *q, void **e, int (*cmp)(void *, void *), void *cmpel); int8_t queue_set_new_data(queue_t *q, uint8_t v); uint8_t queue_get_new_data(queue_t *q); #endif /* __QUEUE_H__ */ ``` ::: :::spoiler queue.c ```c #include "queue.h" #include "queue_internal.h" queue_t *queue_create(void) { queue_t *q = (queue_t *)malloc(sizeof(queue_t)); if(q != NULL) { q->mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); if(q->mutex == NULL) { free(q); return NULL; } pthread_mutex_init(q->mutex, NULL); q->cond_get = (pthread_cond_t *)malloc(sizeof(pthread_cond_t)); if(q->cond_get == NULL) { pthread_mutex_destroy(q->mutex); free(q->mutex); free(q); return NULL; } pthread_cond_init(q->cond_get, NULL); q->cond_put = (pthread_cond_t *)malloc(sizeof(pthread_cond_t)); if(q->cond_put == NULL) { pthread_cond_destroy(q->cond_get); free(q->cond_get); pthread_mutex_destroy(q->mutex); free(q->mutex); free(q); return NULL; } pthread_cond_init(q->cond_put, NULL); q->first_el = NULL; q->last_el = NULL; q->num_els = 0; q->max_els = 0; q->new_data = 1; q->sort = 0; q->asc_order = 1; q->cmp_el = NULL; } return q; } queue_t *queue_create_limited(uintX_t max_elements) { queue_t *q = queue_create(); if(q != NULL) q->max_els = max_elements; return q; } queue_t *queue_create_sorted(int8_t asc, int (*cmp)(void *, void *)) { if(cmp == NULL) return NULL; queue_t *q = queue_create(); if(q != NULL) { q->sort = 1; q->asc_order = asc; q->cmp_el = cmp; } return q; } queue_t *queue_create_limited_sorted(uintX_t max_elements, int8_t asc, int (*cmp)(void *, void *)) { if(cmp == NULL) return NULL; queue_t *q = queue_create(); if(q != NULL) { q->max_els = max_elements; q->sort = 1; q->asc_order = asc; q->cmp_el = cmp; } return q; } int8_t queue_destroy(queue_t *q) { if(q == NULL) return Q_ERR_INVALID; return queue_destroy_internal(q, 0, NULL); } int8_t queue_destroy_complete(queue_t *q, void (*ff)(void *)) { if(q == NULL) return Q_ERR_INVALID; return queue_destroy_internal(q, 1, ff); } int8_t queue_flush(queue_t *q) { if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; int8_t r = queue_flush_internal(q, 0, NULL); if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return r; } int8_t queue_flush_complete(queue_t *q, void (*ff)(void *)) { if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; int8_t r = queue_flush_internal(q, 1, ff); if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return r; } uintX_t queue_elements(queue_t *q) { uintX_t ret = UINTX_MAX; if(q == NULL) return ret; if (0 != queue_lock_internal(q)) return ret; ret = q->num_els; if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return ret; } int8_t queue_empty(queue_t *q) { if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; uint8_t ret; if(q->first_el == NULL || q->last_el == NULL) ret = 1; else ret = 0; if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return ret; } int8_t queue_set_new_data(queue_t *q, uint8_t v) { if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; q->new_data = v; if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; if(q->new_data == 0) { // notify waiting threads, when new data isn't accepted pthread_cond_broadcast(q->cond_get); pthread_cond_broadcast(q->cond_put); } return Q_OK; } uint8_t queue_get_new_data(queue_t *q) { if(q == NULL) return 0; if (0 != queue_lock_internal(q)) return 0; uint8_t r = q->new_data; if (0 != queue_unlock_internal(q)) return 0; return r; } int8_t queue_put(queue_t *q, void *el) { if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; int8_t r = queue_put_internal(q, el, NULL); if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return r; } int8_t queue_put_wait(queue_t *q, void *el) { if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; int8_t r = queue_put_internal(q, el, pthread_cond_wait); if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return r; } int8_t queue_get(queue_t *q, void **e) { *e = NULL; if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; int8_t r = queue_get_internal(q, e, NULL, NULL, NULL); if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return r; } int8_t queue_get_wait(queue_t *q, void **e) { *e = NULL; if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; int8_t r = queue_get_internal(q, e, pthread_cond_wait, NULL, NULL); if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return r; } int8_t queue_get_filtered(queue_t *q, void **e, int (*cmp)(void *, void *), void *cmpel) { *e = NULL; if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; int8_t r = queue_get_internal(q, e, NULL, cmp, cmpel); if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return r; } int8_t queue_flush_put(queue_t *q, void (*ff)(void *), void *e) { if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; int8_t r = queue_flush_internal(q, 0, NULL); r = queue_put_internal(q, e, NULL); if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return r; } int8_t queue_flush_complete_put(queue_t *q, void (*ff)(void *), void *e) { if(q == NULL) return Q_ERR_INVALID; if (0 != queue_lock_internal(q)) return Q_ERR_LOCK; int8_t r = queue_flush_internal(q, 1, ff); r = queue_put_internal(q, e, NULL); if (0 != queue_unlock_internal(q)) return Q_ERR_LOCK; return r; } ``` ::: 1. `queue_create`: - 為新的`queue_t`結構分配內存。 - 初始化用於同步的互斥鎖和條件變量。 - 設置queue結構的其他成員的初始值。 - 返回指向創建的queue的指針。 2. `queue_create_limited`: - 調用`queue_create`以創建新的queue。 - 設置queue的最大元素數(`max_elements`)。 - 返回指向創建的queue的指針。 3. `queue_create_sorted`: - 調用`queue_create`以創建新的隊列。 - 啟用排序,設置`sort`標誌。 - 設置排序順序(升序或降序)和比較函數。 - 返回指向創建的queue的指針。 4. `queue_create_limited_sorted`: - 調用`queue_create`以創建新的隊列。 - 設置最大元素數,啟用指定順序和比較函數的排序。 - 返回指向創建的隊列的指針。 5. `queue_destroy`: - 摧毀queue及其相關的資源,不釋放存儲的元素。 - 如果queue無效,則返回錯誤碼。 6. `queue_destroy_complete`: - 摧毀queue,其相關的資源,並可選擇為每個存儲的元素調用清理函數。 - 如果queue無效,則返回錯誤碼。 7. `queue_flush`: - 從queue中移除所有元素,但不釋放它們。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 8. `queue_flush_complete`: - 從queue中移除所有元素,可選擇為每個元素調用清理函數。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 9. `queue_elements`: - 返回queue中當前元素的數量。 - 如果queue無效或存在鎖定問題,則返回`UINTX_MAX`。 10. `queue_empty`: - 檢查queue是否為空。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 11. `queue_set_new_data`: - 設置queue中的`new_data`標誌。 - 如果不接受新數據,則通知等待的線程。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 12. `queue_get_new_data`: - 返回queue中`new_data`標誌的值。 - 如果queue無效或存在鎖定問題,則返回0。 13. `queue_put`: - 向queue添加元素。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 14. `queue_put_wait`: - 向queue添加元素,如果隊列已滿,則等待。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 15. `queue_get`: - 從queue列中檢索元素。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 16. `queue_get_wait`: - 從queue中檢索元素,如果隊列為空,則等待。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 17. `queue_get_filtered`: - 根據過濾條件從queue中檢索元素。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 18. `queue_flush_put`: - 從queue中移除所有元素並添加新元素。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 19. `queue_flush_complete_put`: - 從queue中移除所有元素,為每個元素調用清理函數,然後添加新元素。 - 如果queue無效或存在鎖定問題,則返回錯誤碼。 :::spoiler queue_internal.c ```c #include "queue.h" #include "queue_internal.h" int8_t queue_lock_internal(queue_t *q) { if (q == NULL) return Q_ERR_INVALID; if(0 != pthread_mutex_lock(q->mutex)) return Q_ERR_LOCK; return Q_OK; } int8_t queue_unlock_internal(queue_t *q) { if (q == NULL) return Q_ERR_INVALID; if(0 != pthread_mutex_unlock(q->mutex)) return Q_ERR_LOCK; return Q_OK; } int8_t queue_destroy_internal(queue_t *q, uint8_t fd, void (*ff)(void *)) { int error = Q_OK; error = queue_set_new_data(q, 0); error = queue_lock_internal(q); error = queue_flush_internal(q, fd, ff); error = pthread_cond_destroy(q->cond_get); free(q->cond_get); error = pthread_cond_destroy(q->cond_put); free(q->cond_put); error = queue_unlock_internal(q); while(EBUSY == (error = pthread_mutex_destroy(q->mutex))) sleepmilli(100); free(q->mutex); free(q); return error; } int8_t queue_flush_internal(queue_t *q, uint8_t fd, void (*ff)(void *)) { if(q == NULL) return Q_ERR_INVALID; queue_element_t *qe = q->first_el; queue_element_t *nqe = NULL; while(qe != NULL) { nqe = qe->next; if(fd != 0 && ff == NULL) { free(qe->data); } else if(fd != 0 && ff != NULL) { ff(qe->data); } free(qe); qe = nqe; } q->first_el = NULL; q->last_el = NULL; q->num_els = 0; return Q_OK; } int8_t queue_put_internal(queue_t *q , void *el, int (*action)(pthread_cond_t *, pthread_mutex_t *)) { if(q == NULL) return Q_ERR_INVALID; if(q->new_data == 0) { return Q_ERR_NONEWDATA; } if(q->num_els == (UINTX_MAX - 1) || (q->max_els != 0 && q->num_els == q->max_els)) { if(action == NULL) { return Q_ERR_NUM_ELEMENTS; } else { while ((q->num_els == (UINTX_MAX - 1) || (q->max_els != 0 && q->num_els == q->max_els)) && q->new_data != 0) action(q->cond_put, q->mutex); if(q->new_data == 0) { return Q_ERR_NONEWDATA; } } } queue_element_t *new_el = (queue_element_t *)malloc(sizeof(queue_element_t)); if(new_el == NULL) { return Q_ERR_MEM; } new_el->data = el; new_el->next = NULL; if(q->sort == 0 || q->first_el == NULL) { if(q->last_el == NULL) q->first_el = new_el; else q->last_el->next = new_el; q->last_el = new_el; } else { queue_element_t *s = q->first_el; queue_element_t *t = NULL; int asc_first_el = q->asc_order != 0 && q->cmp_el(s->data, el) >= 0; int desc_first_el = q->asc_order == 0 && q->cmp_el(s->data, el) <= 0; if(asc_first_el == 0 && desc_first_el == 0) { for(s = q->first_el, t = s->next; s != NULL && t != NULL; s = t, t = t->next) { if(q->asc_order != 0 && q->cmp_el(s->data, el) <= 0 && q->cmp_el(el, t->data) <= 0) { break; } else if(q->asc_order == 0 && q->cmp_el(s->data, el) >= 0 && q->cmp_el(el, t->data) >= 0) { break; } } s->next = new_el; new_el->next = t; if(t == NULL) q->last_el = new_el; } else if(asc_first_el != 0 || desc_first_el != 0) { new_el->next = q->first_el; q->first_el = new_el; } } q->num_els++; pthread_cond_signal(q->cond_get); return Q_OK; } int8_t queue_get_internal(queue_t *q, void **e, int (*action)(pthread_cond_t *, pthread_mutex_t *), int (*cmp)(void *, void *), void *cmpel) { if(q == NULL) { *e = NULL; return Q_ERR_INVALID; } if(q->num_els == 0) { if(action == NULL) { *e = NULL; return Q_ERR_NUM_ELEMENTS; } else { while(q->num_els == 0 && q->new_data != 0) action(q->cond_get, q->mutex); if (q->num_els == 0 && q->new_data == 0) return Q_ERR_NONEWDATA; } } queue_element_t *el_prev = NULL, *el = q->first_el; while(cmp != NULL && el != NULL && 0 != cmp(el, cmpel)) { el_prev = el; el = el->next; } if(el != NULL && el_prev == NULL) { q->first_el = el->next; if(q->first_el == NULL) q->last_el = NULL; q->num_els--; *e = el->data; free(el); } else if(el != NULL && el_prev != NULL) { el_prev->next = el->next; q->num_els--; *e = el->data; free(el); } else { *e = NULL; return Q_ERR_INVALID_ELEMENT; } pthread_cond_signal(q->cond_put); return Q_OK; } ``` ::: 1. `queue_lock_internal` 函數: - 用途:對佇列進行鎖定,防止多執行緒同時訪問。 - 參數:`queue_t *q`,表示佇列的指標。 - 返回值:鎖定成功返回 `Q_OK`,否則返回相應的錯誤碼。 2. `queue_unlock_internal` 函數: - 用途:對佇列進行解鎖,允許其他執行緒訪問佇列。 - 參數:`queue_t *q`,表示佇列的指標。 - 返回值:解鎖成功返回 `Q_OK`,否則返回相應的錯誤碼。 3. `queue_destroy_internal` 函數: - 用途:銷毀佇列,釋放相關資源。 - 參數:`queue_t *q`,表示佇列的指標;`uint8_t fd`,表示某種標誌;`void (*ff)(void *)`,表示釋放函數的指標。 - 返回值:成功返回 `Q_OK`,否則返回相應的錯誤碼。 4. `queue_flush_internal` 函數: - 用途:清空佇列中的元素,釋放相關資源。 - 參數:`queue_t *q`,表示佇列的指標;`uint8_t fd`,表示某種標誌;`void (*ff)(void *)`,表示釋放函數的指標。 - 返回值:成功返回 `Q_OK`,否則返回相應的錯誤碼。 5. `queue_put_internal` 函數: - 用途:將元素放入佇列中。 - 參數:`queue_t *q`,表示佇列的指標;`void *el`,表示要放入佇列的元素;`int (*action)(pthread_cond_t *, pthread_mutex_t *)`,表示某種動作的函數指標。 - 返回值:成功返回 `Q_OK`,否則返回相應的錯誤碼。 6. `queue_get_internal` 函數: - 用途:從佇列中取出符合條件的元素。 - 參數:`queue_t *q`,表示佇列的指標;`void **e`,表示取出的元素的指標;`int (*action)(pthread_cond_t *, pthread_mutex_t *)`,表示某種動作的函數指標;`int (*cmp)(void *, void *)`,表示比較函數的指標;`void *cmpel`,表示比較的元素。 - 返回值:成功返回 `Q_OK`,否則返回相應的錯誤碼。 請注意,這些函數中的錯誤碼(如 `Q_ERR_INVALID`、`Q_ERR_LOCK`、`Q_ERR_MEM` 等)用於指示相應的錯誤情況。此外,這些函數中包含了對多執行緒同步的機制,例如使用了 pthread 的 mutex 和條件變數。 :::spoiler example.c - 完整程式碼 ```c #include <stdio.h> #include <stdlib.h> #include <queue.h> typedef struct { char *test; } test; DEFINE_Q_GET(queue_get_test, test)//獲取元素 DEFINE_Q_DESTROY(queue_destroy_complete_test, test) void free_test(test *t) { if(t->test != NULL) free(t->test); free(t); } int cmp_int_ptr(int *a, int *b) { if(*a < *b) return -1; else if(*a > *b) return 1; else return 0; } void unsorted_mode() { queue_t *q = queue_create(); char *t1 = (char *)malloc(1); char *t2 = (char *)malloc(2); char *t3 = (char *)malloc(4); char *t4 = (char *)malloc(8); test *s1 = (test *)malloc(sizeof(test)); s1->test = t1; test *s2 = (test *)malloc(sizeof(test)); s2->test = t2; test *s3 = (test *)malloc(sizeof(test)); s3->test = t3; test *s4 = (test *)malloc(sizeof(test)); s4->test = t4; queue_put(q, s1); queue_put(q, s2); queue_put(q, s3); queue_put(q, s4); test *t; queue_get_test(q, &t); free_test(t); queue_get_test(q, &t); free_test(t); queue_destroy_complete_test(q, free_test); } void sorted_mode() { queue_t *q = queue_create_sorted(1, (int (*)(void *, void *))cmp_int_ptr); int *t1 = (int *)malloc(sizeof(int)); int *t2 = (int *)malloc(sizeof(int)); int *t3 = (int *)malloc(sizeof(int)); int *t4 = (int *)malloc(sizeof(int)); *t1 = 10; *t2 = 12; *t3 = 1; *t4 = 1; queue_put(q, t1); queue_put(q, t2); queue_put(q, t3); queue_put(q, t4); int *t; queue_get(q, (void **)&t); printf("first int %i\n", *t); free(t); queue_get(q, (void **)&t); printf("second int %i\n", *t); free(t); queue_get(q, (void **)&t); printf("third int %i\n", *t); free(t); queue_get(q, (void **)&t); printf("fourth int %i\n", *t); free(t); queue_destroy_complete(q, NULL); } void sorted2_mode() { queue_t *q = queue_create_limited_sorted(3, 1, (int (*)(void *, void *))cmp_int_ptr); int t1 = 1; queue_put(q, &t1); int t2 = 15; queue_put(q, &t2); int t3 = 3; queue_put(q, &t3); int t4 = 27; queue_put(q, &t4); int t5 = 9; queue_put(q, &t5); int *i; queue_get(q, (void **)&i); printf("first element was %d\n", *i); queue_get(q, (void **)&i); printf("second element was %d\n", *i); queue_get(q, (void **)&i); printf("third element was %d\n", *i); queue_get(q, (void **)&i); printf("fourth element was %p\n", i); queue_get(q, (void **)&i); printf("fifth element was %p\n", i); queue_destroy_complete(q, NULL); } int main(int argc, char *argv[]) { unsorted_mode(); sorted_mode(); sorted2_mode(); return 0; } ``` - free_test函數 - 釋放test結構和其他相關內存 ```c void free_test(test *t) { if(t->test != NULL) free(t->test); free(t); } ``` - cmp_int_ptr函數 - 在queue中做排序 ```c int cmp_int_ptr(int *a, int *b) { if(*a < *b) return -1; else if(*a > *b) return 1; else return 0; } ``` - unsorted_mode函數 - 在非排序模式使用queue ```c void unsorted_mode() { queue_t *q = queue_create();//建立queue //分配記憶體給字符指標變數 char *t1 = (char *)malloc(1); char *t2 = (char *)malloc(2); char *t3 = (char *)malloc(4); char *t4 = (char *)malloc(8); //為測試結構分配記憶體 test *s1 = (test *)malloc(sizeof(test)); s1->test = t1; test *s2 = (test *)malloc(sizeof(test)); s2->test = t2; test *s3 = (test *)malloc(sizeof(test)); s3->test = t3; test *s4 = (test *)malloc(sizeof(test)); s4->test = t4; //將test結構放入queue裡面 queue_put(q, s1); queue_put(q, s2); queue_put(q, s3); queue_put(q, s4); //從queue中取出元素 test *t; queue_get_test(q, &t); free_test(t); queue_get_test(q, &t); free_test(t); //完全銷毀佇列 //使用 queue_destroy_complete_test 函數完全銷毀佇列,同時釋放佇列中所有元素所佔用的記憶體。 //此函數的第二個參數是一個釋放函數,用於釋放每個元素的內存。在這裡,使用 free_test 函數來釋放 test 結構。 queue_destroy_complete_test(q, free_test); } ``` - sorted_mode函數 - 在排序模式下使用queue ```c void sorted_mode() { //建立排序佇列 queue_t *q = queue_create_sorted(1, (int (*)(void *, void *))cmp_int_ptr); //分配記憶體給整數指標變數 int *t1 = (int *)malloc(sizeof(int)); int *t2 = (int *)malloc(sizeof(int)); int *t3 = (int *)malloc(sizeof(int)); int *t4 = (int *)malloc(sizeof(int)); *t1 = 10; *t2 = 12; *t3 = 1; *t4 = 1; //將整數指標放入排序queue queue_put(q, t1); queue_put(q, t2); queue_put(q, t3); queue_put(q, t4); //從排序佇列中取出元素並在使用完畢後進行釋放 int *t; queue_get(q, (void **)&t); printf("first int %i\n", *t); free(t); queue_get(q, (void **)&t); printf("second int %i\n", *t); free(t); queue_get(q, (void **)&t); printf("third int %i\n", *t); free(t); queue_get(q, (void **)&t); printf("fourth int %i\n", *t); free(t); //完全銷毀排序佇列 queue_destroy_complete(q, NULL); } ``` - sorted2_mode函數 - 在有限排序模式下使用queue ```c void sorted2_mode() { //建立有限排序queue //第1個參數是queue大小,第2個參數是每次插入時保留元素的數量,第3個參數是比較函數 queue_t *q = queue_create_limited_sorted(3, 1, (int (*)(void *, void *))cmp_int_ptr); //將值放到queue裡面 int t1 = 1; queue_put(q, &t1); int t2 = 15; ueue_put(q, &t2); int t3 = 3; queue_put(q, &t3); int t4 = 27; queue_put(q, &t4); int t5 = 9; queue_put(q, &t5); //將元素輸出 //使用queue_get函數將元素取出 int *i; queue_get(q, (void **)&i); printf("first element was %d\n", *i); queue_get(q, (void **)&i); printf("second element was %d\n", *i); queue_get(q, (void **)&i); printf("third element was %d\n", *i); queue_get(q, (void **)&i); printf("fourth element was %p\n", i); queue_get(q, (void **)&i); printf("fifth element was %p\n", i); //銷毀queue queue_destroy_complete(q, NULL); } ``` :::