2014-01-11 32 views
0

我使TDataset後裔異步,而不是sleepProcessMessages在主線程中它通過來自網絡線程的事件工作。因此,當記錄就緒時,它調用TDataset與DBGrid的線程競賽

procedure TMySqlQuery.OrdinalOnDataReady(Sender: TObject); 
begin 
    AddToLog('OrdinalOnDataReady'); 
    FDataAvailable := true; // used in IsCursorOpen 
    inherited Open; 
    if Assigned(FParentOnDataReady) then 
     FParentOnDataReady(self); 
end; 

它的工作原理,但有時我有問題,與GetRecord通過Open從這個線程中調用和DBGrid中的DrawCells從窗體的ProcessMessages從主線程中調用的DBGrid的GetFieldData。通過登錄這兩個功能我看

[17:10:39] RecordToBuffer row 0 
[17:10:39] len = 17 buf : 
00 E0 10 C3 00 0A 00 00 00 F0 10 C3 00 0B 00 00 | .ïœ.ï「.....ÿ€.ï「.... 
00 | . 
[17:10:40] RecordToBuffer row 1 
[17:10:40] len = 17 buf : 
00 00 FF C3 00 25 00 00 00 10 11 C3 00 0B 00 00 | ..ÿï「.%.....ï「.... 
00 | . 
[17:10:40] ActiveBuffer 
[17:10:40] len = 17 buf : 
00 E0 10 C3 00 0A 00 00 00 F0 10 C3 00 0B 00 00 | .ïœ.ï「.....ÿ€.ï「.... 
00 | . 
... 
more ActiveBuffer 
... 
[17:10:40] ActiveBuffer 
[17:10:40] len = 17 buf : 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ 
00 | . 
[17:10:40] len = 8 buf : 
00 00 00 00 00 00 00 00 | ........ 

,並在休息的時候斷言列ActiveBuffer數據是零,我可以看到的DBGrid試圖讀取行比GetRecord readed進入自己的內部FBuffers更高。例如,如果斷言在GetFieldData第3行觸發 - FBuffers從Recordset中可用的總共36行填充到第2行。當我用F8逐步調試GetRecord時,沒有錯誤utnil,我按下F9鍵並斷言另一條記錄。

我不太明白DBGridTDataset(甚至堆棧跟蹤是巨大的)是如何工作的,但是可以解決這個線程競爭嗎?

+0

不允許同時從兩個線程訪問TDataSet。 TDataSet不是線程安全的。 –

+1

喬安娜卡特有一組關於TDataSet內部的文章。也許你仍然可以在某處找到它們......對於我從使用TDbf的Delphi 5體驗中所記得的內容,db-aware控件只關心緩衝區的數量,例如,如果你報告你有10個緩衝區數量 - 控制是可以自由閱讀的。如果你的緩衝區沒有準備好 - 那麼不要報告你有10個緩衝區。 –

+0

@ Arioch'The - Joannas的文章在哪裏? – Branko

回答

0

解決方案很簡單:因爲TDataset的FBuffers(來自Data.DB)中的數據如果沒有初始化就填充0,所以可以通過GetRecord找到填充的ActiveBuffer,或者通過將另一個標記字節添加到記錄中並且不分配0 GetRecord。 因此,如果DBGrid試圖讀取未初始化的數據,我檢查GetFieldData中的標記,如果0結果爲false並退出。由於DBGrid不止一次將數據提取到同一個單元格,我仍然使用適當的數據填充數據。 它是解決方法,但它的工作原理。