2012-10-11 65 views
2

使用一個Indy 10 TCP命令處理程序,每當我得到一個命令時,我將一行插入數據庫,然後從數據庫讀取整個故事來更新字符串網格。關鍵部分能幫助解決這個問題嗎?

我使用AnyDac數據庫組件及其文檔說「每個時刻必須使用一個連接對象和所有與它相關的對象(如TADQuery,TADTransaction等)」。

如果我「慢慢地」發送TCP命令,沒有問題。如果我「快速」發送它們(雖然AnyDac仍在顯示SQL遊標,但我得到一個異常EDatabaseError「字段未找到」 - 但它當然存在。)

當我收到TCP命令時, UM_使用PostMessage的,以我的主要形式。

認爲的情況是,主要的形式是從表中讀取所有行作爲第一個TCP命令的結果,而TCP命令處理程序是,雖然中途插入一個新行作爲第二個命令的結果 - 因此當我調用ADQuery1.FieldByName()時出現「字段未找到」

這聽起來像是問題嗎?

如果是這樣,我該如何預防它?可以使用關鍵部分(其中,主線程?)?或者有其他方法嗎?


[更新]我剛剛意識到 - 這不能是一個線程問題(我認爲)。當我得到一個TCP命令時,我使用PostMessage()將UM_發送到我的主窗體。所以,不管TCP命令有多快,我的主窗體只能通過它的消息隊列處理一個UM_。 TCP命令處理程序只是發送該消息的單一行 - 沒有d/b訪問權限。

但我不明白的是,如果在TCP命令之間留下「一段時間」一切都很好,但是如果我「快速」發送它們,那麼我會得到異常情況,說該行中沒有這樣的字段的表格。


[更新] 其實我終於解決了它,並使用相當慢到更新TStringGrid的問題了。 Tehre是使它更快的方法,但我決定將它轉換爲TDbGrid,它可以非常快速地更新。

+3

在每個線程同時訪問一個數據庫,你應該使用專用TADConnection,或者你應該序列從多個線程訪問TADConnection和相關對象。首先更簡單並且推薦。更多關於此: http://www.da-soft.com/anydac/docu/Multi_Threading.html –

+0

+1但請參閱我的更新。我不認爲這可能是一個線程問題。我認爲我這樣想是錯的。 – Mawg

+2

「找不到字段」可能有很多原因: 1)數據集關閉。 2)爲沒有字段的SELECT打開數據集,然後在另一個上下文中使用,期望該字段存在。 3)對數據集的多線程訪問會殺死內部結構。 4)只是你的代碼中的錯誤,它期望字段,但是SELECT不返回這個字段。 5)DB結構在運行中發生變化,所以表中不再存在該字段。 –

回答

3

聽起來好像您正在後臺線程中運行的TCP命令處理程序中更新AnyDac數據庫,並從主線程讀取AnyDac數據庫。由於AnyDac說他們不支持多線程訪問,這會產生問題。

一種方法是嘗試使所有參與線程排隊並等待訪問AnyDac數據庫。這違背了使用多個線程開始的目標 - 爲什麼要使用多個線程,如果你要做的就是讓它們排隊並按順序執行?如果您計劃在您的應用的重繪邏輯中獲取該鎖,則添加互斥鎖(如關鍵部分)會增加您創建死鎖情況的機率,尤其是。你絕對不想鎖定你的重繪邏輯。

另一種方法是將數據庫更新移動到主線程中。還有一些線程同步需要執行此操作,但負責人位於後臺線程,而不是您的主線程。

將數據庫更新移動到主線程中的一種比較簡單的方法是讓TCP命令處理程序在主窗口中發佈自定義UM_消息(如您​​已經這樣做)將數據附加到消息。消息處理程序從消息中選擇數據,使用數據更新數據庫,並處理附加到消息的數據。

通過這種方法,所有對AnyDac數據庫對象的訪問都發生在主線程中,所以沒有多線程問題。除非有人在重繪循環中調用Application.ProcessMessages這樣的傻事,這應該可以解決重繪過程中發生的數據庫更新問題。

+0

+1但是,請參閱我的更新,我不認爲這可能是線程問題,我認爲我錯了。 – Mawg

2

如果您將數據傳遞給PostMessage(),則必須確保在處理主線程中的消息期間數據仍然有效。最簡單的方法就是做你的處理程序如下:

  • 創建新的對象
  • 必要的數據複製到新創建的對象
  • 調用PostMessage的與新的對象發送消息作爲參數到消息


    procedure ... 
    var MsgData: TMsgData; 
    begin 
     MsgData := TMsgData.Create(ACommand); 
     PostMessage(MainFormHWND, WM_MYMSG, Integer(MsgData), 0); 
    end 

在處理程序中用於消息

  • 過程消息
  • 自由對象


    procedure MainForm.HandleMsg(var M: TMessage); 
    var MsgData: TMsgData; 
    begin 
     MsgData := TMsgData(M.WParam); 
     // Process command 
     MsgData.Free(); 
    end; 

相關問題