實作缺失位於函式 con_pop
中:
node_t *node = queue->first; /* Node to be removed */
node_t *new_header = queue->first->next; /* become the first in the queue */
/* Queue is empty */
if (!new_header) {
mtx_unlock(queue->first_mutex);
return NULL;
}
其中指標 node
要提取的節點不應為 queue->first
,因為第一次執行 pop 操作時,會將 dummy 節點取出。 後者用於保證 queue 的頭尾 (first
以及 last
) 一致性。倘若將其提取出來,queue 會在經歷至少一次的 pop/push 操作並且只剩一個節點時,無法將最後一個節點取出,因為本實做需要 dummy 節點總是存在。
也就是說,發生問題時,即便 queue 中仍然有未處理的節點,應用程式還是會拿到 NULL (表示 queue 中沒有未處理的節點),而不是最後一個節點的內容。
因此,此程式實際運作時,最後一個要提取存放 kill signal 的節點的 pop thread 總是無法完成提取操作,進而無法讓 thrd_join
完成等待。
可以將 con_pop
修改為:
void *con_pop(con_queue_t *queue)
{
mtx_lock(queue->first_mutex);
-- node_t *node = queue->first; /* Node to be removed */
-- node_t *new_header = queue->first->next; /* become the first in the queue */
++ node_t *node = queue->first->next; /* Node to be removed */
/* Queue is empty */
-- if (!new_header) {
++ if (!node) {
mtx_unlock(queue->first_mutex);
return NULL;
}
/* Queue not empty: retrieve data and rewire */
void *return_value = node->value; /* BBB */
-- queue->first->next = new_header;
++ queue->first->next = node->next;
mtx_unlock(queue->first_mutex);
/* Free removed node and return */
free(node);
return return_value;
}
以使得執行 pop 操作時,總是提取從 first
算起的第二個節點,也就是應用程式感興趣的最舊的節點 (queue->first->next
),以解決第一次呼叫 con_pop
時,將 dummy 節點移出 queue 的問題。
答案 BBB (L17) 貌似不是 node->value
?