在看 apue 第 21 章 與網路列印機通信一章時,發現一段關于鏈表操作的代碼有問題,現在摘出來讓大家 review 一下,先上代碼:
printd.c
這是列印服務的源代碼,在列印時,用戶通過 print 命令提交待列印的檔案,print 命令通過 tcp 與 printd 服務通訊,
將檔案及列印相關的引數傳遞給后者;對于每個客戶,printd 服務會創建一個 worker 結構節點,
放在一個由 workers 變數指定了頭的雙向鏈表中,所以這段代碼本質上就是簡單的雙向鏈接操作:
1 void add_worker (pthread_t tid, int sockfd) 2 { 3 struct worker_thread *wtp; 4 if ((wtp = malloc (sizeof (struct worker_thread))) == NULL) { 5 log_ret ("add_worker: can't malloc"); 6 pthread_exit ((void *)1); 7 } 8 9 wtp->tid = tid; 10 wtp->sockfd = sockfd; 11 12 log_msg ("prepare to add worker"); 13 pthread_mutex_lock (&workerlock); 14 15 wtp->prev = NULL; 16 wtp->next = workers; 17 if (workers == NULL) 18 workers = wtp; 19 else 20 workers->prev = wtp; 21 22 pthread_mutex_unlock (&workerlock); 23 }
重點就是 15-20 這 6 行啦(原文p633,代碼499-504行),當第一次加入節點時, workers 為 NULL,所以走第一個條件分支,這沒有問題;
但是再加入節點時, workers 不為 NULL,此時走 else 分支,將當前頭的上一個節點設定為待插入的新節點 wtp,
到現在還好,可是等等,怎么就沒下文了?!這個節點還沒完全加入鏈表呢……
正確的做法應該是在結尾前再加一句:
else { workers->prev = wtp; workers = wtp; }
這樣才能算完嘛,道理就不多說了,不信自己畫個鏈表看看,下面給出優化后的完整代碼:
1 void add_worker (pthread_t tid, int sockfd) 2 { 3 struct worker_thread *wtp; 4 if ((wtp = malloc (sizeof (struct worker_thread))) == NULL) { 5 log_ret ("add_worker: can't malloc"); 6 pthread_exit ((void *)1); 7 } 8 9 wtp->tid = tid; 10 wtp->sockfd = sockfd; 11 pthread_mutex_lock (&workerlock); 12 13 wtp->prev = NULL; 14 wtp->next = workers; 15 if (workers != NULL) 16 workers->prev = wtp; 17 18 workers = wtp; 19 20 pthread_mutex_unlock (&workerlock); 21 }
好吧,我承認作為經典著作也會有這種低級錯誤,
今天的吹毛求疵就到這里,作為一個有職業素養的程式員,不在雞蛋里挑出骨頭來不罷休,嘿嘿……
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/77502.html
標籤:Linux
