## 說碼解扣-- 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);
}
```
:::