Einzelnen Beitrag anzeigen

DelphiManiac

Registriert seit: 5. Dez 2005
742 Beiträge
 
#1

Deadlock beim stoppen eines Arbeiter Threads

  Alt 10. Mär 2007, 19:37
Hallo und guten Abend,

ich habe folgendes Programmkonstrukt:

1. Hauptthread (der die VCL bedient)
2. Arbeiterthread, der bestimmte Werte über eine Schnittstelle holt und diese über Synchronize an den Hauptthread übergibt.

Ich habe nun folgendes Problem, der 2. Thread soll ja weitesgehend selbsständig im Hintergrund laufen, und sich immer dann melden, wenn er neue Werte hat...

Das klappt auch, mein Problem ist, dass ich ihn synchronisieren muss mit dem Hauptthread, und zwar genau dann, wenn ich vom Hauptthread auch auf die Schnittstelle zugreifen will..

aThread.Suspend; Kommt nicht Frage, da ich nie genau weiß in welchem Zustand mein Schnittstellenobjekt gerade ist(könnte ja sein, dass er gerade gesendet hat)..

Ich muss also den Thread in einem definierten Zustand stoppen können, habe das
zurzeit folgendermaßen gelöst:

Delphi-Quellcode:
procedure TCyclicData.Execute;
var
  I: Integer;
  merkeTimeOutProz: procedure (Sender:TObject) of object;
begin
  while Not(Terminated) do
  begin
// Synchronize(fSTK.Kommunikation.Sch);
    merkeTimeOutProz:=fSTK.Kommunikation.OnTimeOut;
   fSTK.Kommunikation.OnTimeOut:=Self.ShowTimeOut;

// if MaskeAnalogAusgangAktiv then exit;
    feinDataset.aktuellerFlow:=fSTK.aktFlow;
    feinDataset.Summation:=fSTK.Summation;
    feinDataset.Status:=fSTK.Status;
    feinDataset.Counts:=fSTK.Kommunikation.Counts;
// feinDataset.Dezimalstelle:=fSTK.DezimalStelle;
    // =====KALIBRIERUNG======//
    if (MaskeKalibrierungAktiv) then
    begin
      if (fSTK.isMulti) then
      begin
        for I := 1 to length(fChannels) do
        begin
          // Laufe jeden verfügbaren Kanal durch
          if fChannels[i] then
          begin
            fSTK.KanalWechsel:=I;
            fDataSetKalib[I].KanalNr:=I;
            fDataSetKalib[I].KanalAktiv:=true;
            fDataSetKalib[I].DeltaTempCorr:=fSTK.DeltaTempCorr;
            fDataSetKalib[I].T2:=fSTK.T2;
            fDataSetKalib[I].DeltaTRoh:=fSTK.DeltaTRoh;
          end; // of if fChannels[i] then
        end; // of for I := 0 to length(fChannels) - 1 do
      end; // of if fSTK.isMulti then
      Synchronize(SyncKanalData);
      feinDataset.T2:=fSTK.T2;
      feinDataset.DeltaTRoh:=fSTK.DeltaTRoh;
    end; // of if MaskeKalibrierungAktiv then
    // =====SONSTIGES======//
    if (MaskeSonstigesAktiv) then
    begin
      feinDataset.aktuellerFlow:=fSTK.aktFlow;
      feinDataset.aktFlowSkaliert:=fSTK.aktFlowSkaliert;
      feinDataset.DeltaTRoh:=fSTK.DeltaTRoh;
    end; // of if MaskeSonstigesAktiv then
    if (MaskeDataloggingAktiv) then
    begin
      // Lese Anzahl DS
      feinDataset.DataSetCounts:=fSTK.DataSetCounts;
      fSTK.DataLogConfig;
    end; // of if (MaskeDataloggingAktiv) then
//-----------------------------------> WICHTIGER BEREICH
    if (fShouldStopp) then
    begin
      fSyncObj.Acquire;
      fIsStopped:=true;
      fSyncObj.Release;
      while fShouldStopp do
      begin
        Sleep(10);
        if Self.Terminated then exit;
      end;
//-----------------------------------> WICHTIGER BEREICH
      fSyncObj.Acquire;
      isStopped:=false;
      fSyncObj.Release;
    end
    else
    begin
      fSyncObj.Acquire;
      isStopped:=false;
      fSyncObj.Release;
    end; // of if (fShouldStopp) then
// if MaskeAnalogAusgangAktiv then exit;
   fSTK.Kommunikation.OnTimeOut:=merkeTimeOutProz;
   Synchronize(Self.SyncOnNewData);
    Sleep(100);
  end;
end;

Im Hauptthread setzte ich also die Variable fshouldstopp und warte dann bis der Thread dann die Variable isStopped gesetzt hat, um zuwissen, dass er gestoppt hat.

Das passiert folgendermaßen (sollte besser mit Signalen arbeiten, oder??)
Delphi-Quellcode:
(*******************************************************************************
  Prozedur zum stoppen des Hintergrund Tasks
*******************************************************************************)

procedure TFrmMain.StoppBackgroundTask;
begin
  if Assigned(aCyclicDataThread) then
  begin
    aCyclicDataThread.PleaseStopp;
    while (Not aCyclicDataThread.isStopped) do
    begin
      if Not(einSTK.Kommunikation.Schnittstelle.isConnected) then exit;

      if(Application.Terminated) then exit;
    end; // of while (Not aCyclicDataThread.isStopped) do
  end; // of if Assigned(aCyclicDataThread) then
end;// of procedure TFrmMain.StoppBackgroundTask;
////////////////////////////////////////////////////////////////////////////////
Könnt ihr mir helfen, wie ich das besser lösen kann??

Danke euch
  Mit Zitat antworten Zitat