我寫多線程應用程序的窗口,其中線程:
A - 是一個視窗形式處理用戶交互和處理來自B.
B中的數據 - 偶爾產生數據並將其傳遞兩個APostMessage的偶爾丟失的消息
線程安全隊列用於將數據從線程B傳遞給A.使用窗口臨界段對象保護入隊和出隊函數。
如果在調用enqueue函數時隊列爲空,則函數將使用PostMessage告訴A隊列中有數據。該函數檢查以確保對PostMessage的調用已成功執行,並且如果PostMessage不成功(PostMessage尚未失敗),則重複調用PostMessage。
這很好用了一段時間,直到一臺特定的計算機開始失去偶爾的信息。通過失去我的意思是,PostMessage在B中成功返回,但A永遠不會收到消息。這會導致軟件出現凍結。
我已經想出了一些可接受的解決方法。我很有興趣知道爲什麼Windows會丟失這些消息,以及爲什麼這隻發生在一臺計算機上。
以下是代碼的相關部分。
// Only called by B
procedure TSharedQueue.Enqueue(AItem: TSQItem);
var
B: boolean;
begin
EnterCriticalSection(FQueueLock);
if FCount > 0 then
begin
FLast.FNext := AItem;
FLast := AItem;
end
else
begin
FFirst := AItem;
FLast := AItem;
end;
if (FCount = 0) or (FCount mod 10 = 0) then // just in case a message is lost
repeat
B := PostMessage(FConsumer, SQ_HAS_DATA, 0, 0);
if not B then
Sleep(1000); // this line of code has never been reached
until B;
Inc(FCount);
LeaveCriticalSection(FQueueLock);
end;
// Only called by A
function TSharedQueue.Dequeue: TSQItem;
begin
EnterCriticalSection(FQueueLock);
if FCount > 0 then
begin
Result := FFirst;
FFirst := FFirst.FNext;
Result.FNext := nil;
Dec(FCount);
end
else
Result := nil;
LeaveCriticalSection(FQueueLock);
end;
// procedure called when SQ_HAS_DATA is received
procedure TfrmMonitor.SQHasData(var AMessage: TMessage);
var
Item: TSQItem;
begin
while FMessageQueue.Count > 0 do
begin
Item := FMessageQueue.Dequeue;
// use the Item somehow
end;
end;
如果您可以提供您鎖定/解鎖/推送/彈出/檢查隊列的關鍵區域的代碼摘錄,這將有所幫助。 – 2009-01-14 22:24:28