マルチスレッド Windows アプリケーションを作成しました。ここで、スレッド:
A – ユーザーの操作を処理し、B からのデータを処理する Windows フォームです
。B – 時々データを生成し、2 つの A に渡します。
スレッド セーフ キューは、スレッド B から A にデータを渡すために使用されます。エンキューおよびデキュー機能は、Windows クリティカル セクション オブジェクトを使用して保護されます。
エンキュー関数が呼び出されたときにキューが空の場合、関数は PostMessage を使用して、キューにデータがあることを A に伝えます。この関数は、PostMessage への呼び出しが正常に実行されていることを確認し、成功していない場合は PostMessage を繰り返し呼び出します (PostMessage はまだ失敗していません)。
これは、ある特定のコンピューターが時折メッセージを失い始めるまで、かなり長い間うまくいきました。失うとは、PostMessage が B で正常に返されるが、A がメッセージを受信しないことを意味します。これにより、ソフトウェアがフリーズしたように見えます。
私はすでにいくつかの許容できる回避策を考え出しました。Windows がこれらのメッセージを失っている理由と、これが 1 台のコンピューターでのみ発生している理由を知るのは興味深いことです。
コードの関連部分を次に示します。
// 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;