我编写了一个多线程 Windows 应用程序,其中线程:
A – 是一个处理用户交互并处理来自 B 的数据的 Windows 窗体
。B – 偶尔生成数据并将两个 A 传递给它。
线程安全队列用于将数据从线程 B 传递到 A。入队和出队函数使用 Windows 临界区对象进行保护。
如果调用 enqueue 函数时队列为空,该函数将使用 PostMessage 告诉 A 队列中有数据。该函数检查以确保对 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;