在多模組協同的軟體系統中,訊息處理的時序正確性至關重要。本文記錄一個真實專案案例:模組 A 與模組 B 透過訊息隊列通訊,模組 A 發送攜帶用戶號碼與序列號的訊息後,將用戶號碼按序列號存入全域變量;模組 B 處理完畢後原樣返回。模組 A 收到回覆時,依序列號查找原發送號碼並比對。自測階段發現比對失敗,導致後續流程中斷。
模組 A 的關鍵流程如下:
關鍵問題在於步驟 2 的休眠:模組 B 處理極快,在模組 A 休眠期間就已返回訊息。此時模組 A 尚未完成步驟 3 的拷貝,全域變量仍為空值,導致步驟 6 比對失敗。
將休眠代碼註釋後重測,問題消失。根本修復:將拷貝全域變量移至發送訊息之前,保留休眠不影響正確性。修改後流程:
send_msg_to_B(msg);
sleep(DELAY_MS); // 危險:模組 B 可能在此期間已返回
copy_to_global(seq, user_id); // 太晚了!
recv_msg_from_B(&reply);
if (strcmp(global[reply.seq], reply.user_id) != 0) error();
copy_to_global(seq, user_id); // 先寫入,建立有效上下文
send_msg_to_B(msg);
sleep(DELAY_MS); // 現在安全了
recv_msg_from_B(&reply);
if (strcmp(global[reply.seq], reply.user_id) != 0) error();
時序錯誤隱蔽且破壞力強,往往在高負載或不同機器上才暴露。養成「先建立上下文、再觸發異步操作」的編程習慣,配合完善的日誌體系,是避免此類缺陷的關鍵。