簡體   English   中英

Delphi:通過TThread驗證DataSnap連接

[英]Delphi: Verify DataSnap connection via TThread

我們有一個應用程序,用戶可以在其中與我們交談,它工作正常,他創建了新的對話,我們聊天,沒關系。 但是,在開始聊天之前,他需要連接到DataSnap Server,這就是我要創建線程的地方。 每隔5分鍾,計時器將觸發他的事件以創建線程並嘗試在服務器上進行連接,如下所示:

我的主題:

unit UThreadSnapConnection;

interface

uses
  System.Classes, System.SysUtils, Data.SqlExpr;

type
  TThreadSnapConnection = class(TThread)
  private
    FSnap: TSQLConnection;
    procedure TryToConnect;
  protected
    procedure Execute; override;
    constructor Create;
  public
    DMSnap: TSQLConnection;
    HostName: String;
    Port: String;
  end;

implementation

{ TThreadSnapConnection }

constructor TThreadSnapConnection.Create;
begin
  inherited Create(True);
  FreeOnTerminate := True;
end;

procedure TThreadSnapConnection.TryToConnect;
begin
  try
    FSnap := DMSnap.CloneConnection;
    FSnap.Connected := False;

    try
      FSnap.Connected := True;
    except

    end;

    if FSnap.Connected then
      DMSnap.Connected := True;
  finally
    FreeAndNil(FSnap);
  end;
end;

procedure TThreadSnapConnection.Execute;
begin
  Synchronize(TryToConnect);
end;

end.

我的計時器:

procedure TMyDataModuleSnap.TimerSnapTimer(Sender: TObject);
var
  MyThread: TThreadSnapConnection;
begin
  if not(MySQLConnection.Connected) then
  begin
    MyThread := TThreadSnapConnection.Create;

    MyThread.DMSnap   := MySQLConnection;
    MyThread.HostName := 'localhost';
    MyThread.Port     := '211';

    MyThread.Resume;
  end;
end;

我正在做的是嘗試連接到服務器,如果它可以正常工作,那么它將使我的數據模塊連接。

我的問題是,每次上線

FSnap.Connected := True;

執行它會使應用程序凍結1〜2秒鍾,而我創建線程的原因是不凍結。 據我所知,它不應該打擾所有應用程序,因此我開始認為這可能是將Connected屬性設置為True時所做的工作,無論該屬性是否為線程,它都會凍結。

嘗試連接時有什么方法不凍結嗎?

這是我的第一個線程,也許我只是誤解了一些東西,這不是線程的工作方式,但是,如果不是,那我就需要知道,或者至少要了解我在做什么錯。

編輯:我正在做的測試是,我在不啟動服務器的情況下啟動應用程序,因此它將嘗試連接失敗,並且我的數據模塊也將無法連接。

有兩種選擇:

  1. 在創建計時器的線程中執行TTimerOnTimer事件時,您可以考慮在主線程之外創建實例
  2. 您可以考慮使用TThread類實例

以下內容適用於#2。

在線程的Execute過程中使用TEvent ,可以在執行下一個代碼塊之前等待FInterval時間。
Terminated屬性設置為True ,此方法允許Execute方法在間隔計數期間也立即返回,這與采用TThread.Sleep(FInterval); 調用,它將在指定的時間內凍結線程本身。

完成后,可以選擇使用TNotifyEvent通知主線程。

TMyThread = class(TThread)
  private
    FInterval: Integer;
    FTerminateEvent: TEvent;
  protected
    procedure Execute; override;
    procedure TerminatedSet; override;
  public
    OnEndJob: TNotifyEvent;
    constructor Create(Interval: Cardinal; CreateSuspended: Boolean);
    destructor Destroy; override;
end;

constructor TMyThread.Create(Interval: Cardinal; CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  FInterval := Interval;
  FTerminateEvent := TEvent.Create(nil, False, False, '');
end;

destructor TMyThread.Destroy;
begin
  FTerminateEvent.Free;
  inherited;
end;

procedure TMyThread.TerminatedSet;
begin
  inherited;
  FTerminateEvent.SetEvent;
end

procedure TMyThread.Execute;
begin
  while not Terminated do begin
    //do your stuff

    //notify your connection to the main thread if you want
    if Assigned(OnEndJob) then
      Synchronize(procedure
          begin
            OnEndJob(Self);
          end);

    //wait fo some amount of time before continue the execution
    if wrSignaled = FterminateEvent.WaitFor(FInterval) then
      Break;
  end;
end;

不要synchonize你想在一個線程中執行的代碼:Delphi中syncronized塊調用線程總是執行。

我本來希望發表評論而不是回答,但是我缺乏聲譽。 閱讀以下內容時應考慮的一些事項。

在兩行之間閱讀時,您似乎已連接到本地SQL Server。 訪問很少會導致連接斷開,因此您設置了一個計時器,每5分鍾檢查一次,並在必要時重新建立連接。

此方法有效,但是您發現連接嘗試會阻止程序執行,直到建立連接為止,因此您希望將此操作移至工作線程。

正如fantaghirocco所說,“同步”使代碼在主程序線程中運行。 我的理解是,此代碼在處理完主線程中的所有消息之后運行,因此您可以通過使計時器發布消息以及關聯的消息處理程序調用TryToConnect(在這種情況下以主窗體聲明TryToConnect)來實現相同的結果。

同步是允許線程與主線程進行交互的最簡單方法,而不必擔心兩個或多個線程同時訪問同一對象。

為了防止連接過程阻塞主程序線程,必須在TThread后代的Execute方法中設置MySQLConnection Connected屬性(未封裝在對Synchronize的調用中)。

但是這樣做會帶來工作線程和主程序同時訪問MySQLConnection的風險。 為了防止這種情況,您需要引入一個關鍵部分或類似內容。 如果不熟悉,請在RAD Studio幫助中檢查TCriticalSection。 有一個關於關鍵部分的部分和一個示例。

然后,主程序和線程都會將對MySQLConnection的所有調用封裝在關鍵部分try finally塊中:

FLock.Acquire;
try
  {code accessing MySQLConnection goes here}
finally
  FLock.Release;
end;

其中FLock是TCriticalSection對象。

任何試圖獲取FLock的線程(如果已被另一個線程獲取)將被阻止,直到釋放FLock。 這意味着僅當工作線程已經在嘗試連接時用戶嘗試訪問MySQLConnection時,主線程才會被阻止。

更新:

首先,下面是一個由兩個單元組成的簡單程序; Unit1包含主窗體(創建新應用程序時將顯示的內容)。 第二個單元Unit2包含一個線程。 由於您的線程似乎在一個單獨的單元中,因此我這樣做了。

我已經在TForm1中添加了一個按鈕和一個關鍵部分(在Uses子句中添加了System.SyncObjs)。 在Button1的click事件中,我創建一個TMyThread實例(在您的代碼中,它將由timer事件處理):

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    FLock: TCriticalSection;
  end;

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyThread.Create;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FLock := TCriticalSection.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FLock.Free;
end;

Unit2包含線程。 execute方法是一炮而制。 將Unit1添加到實現中的uses子句中,以使代碼可以訪問Form1變量:

type
  TMyThread = class (TThread)
  protected
    procedure Execute; override;
  public
    constructor Create;
  end;

implementation

uses Unit1;


{ TMyThread }

constructor TMyThread.Create;
begin
  inherited Create (False);
end;

procedure TMyThread.Execute;
begin
  with Form1 do begin
    FLock.Acquire;
    try
      {access MySQLConnection methods here}
    finally
      FLock.Release;
    end;
  end;
end;

當您運行此簡單程序並單擊Button1時,將創建一個單獨的線程並運行execute方法,然后銷毀該線程。 每次您單擊Button1都會重復此過程。

如果放在在1單元斷點MyThread := TMyThread.Create線,並在UNIT2另一個斷點在FLock.Acquire行,運行程序,並單擊Button1,代碼將停止在主線程; 左窗格中顯示的線程ID。 如果單擊F9繼續執行程序,它將在Unit2斷點處停止。 您會注意到線程ID現在有所不同,並且IDE底部的“線程狀態”窗口現在列出了這個額外的線程。 當再次按F9鍵時,此新線程消失。

該程序不執行任何操作,但是您將在該線程中運行所需的任何MySQLConnection代碼放在​​“嘗試最終”塊中的注釋處。

在主線程中,無論何時訪問MySQLConnection的方法,您都還需要將它們封裝在FLock try finally塊中。 例如,如果您有一個TClientDataSet連接到一個TDataSetProvider,而TDataSetProvider連接到了一個連接到MySQLConnection的TSQLDataSet,則打開TClientDataSet必須封裝在此FLock中。最后嘗試:

begin
  FLock.Acquire;
  try
    CDS.Open;
  finally
    FLock.Release;
  end;
end;

其中CDS是TClientDataSet。

您打算在線程中運行的代碼基本上會關閉連接並重新打開它。 關鍵部分的一個好處(如果配置正確,並且對MySQLConnection的所有訪問都受到關鍵部分的保護),它將防止在用戶查詢過程中關閉連接。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM