Einzelnen Beitrag anzeigen

zorro08

Registriert seit: 8. Mär 2008
4 Beiträge
 
#4

Re: Synchronisieren von hauptthread und Teilthread

  Alt 9. Mär 2008, 19:03
Nach einigen Stunden Beschäftigung mit dem Thema sieht die Situation so aus:

1. Das Sperren des Hauptthreads klappt mit WaitForSingleObject(Event_0,INFINITE). Und zwar so gut, dass er bei falscher Anwendung niemals wieder ans Laufen kommt.

Falsche Anwendung bedeutet:

a) Entweder wurde nicht organisiert, dass mindestens ein Event, z.B. von einem Thread, kommt.
b) Oder mitten in die TimerRoutine platzt dann ein BtnClickEvent, der ebenfalls WaitForSingleObject(Event_0,INFINITE) enthält und damit seinerseits auf einen Event wartet, der später eigentlich von der Timerroutine ausgelöst werden sollte, um die Lock/Unlock-Kette am laufen zu halten.

Klassischer Deadlock !

Die (für mich) richtige Anwendung wäre:

o Es wird ein Vorratsevent direkt nach dem Erzeugen des Events aktiviert

Delphi-Quellcode:
event0 := CreateEvent(nil, False, False, nil);
SetEvent(Event0);
o Dann kommen die Threads oder der hauptthread mittes WaitForSingleObject( Event_0, 10 ) irgenwann zufällig zum Zuge
o nach der Datenbearbeitung oder - Nutzung im Thread/HauptThread wird direkt wieder ein Event aktiviert

Delphi-Quellcode:
//----------------------------------------------
procedure TForm1.Timer1Timer(Sender: TObject);
//----------------------------------------------
var wfmo: DWORD;
    s: string;
    tp2: int64;
    ccc: integer;
begin

  Timer1.Enabled:=FALSE;

  if fn_GetTimerSec(tp1) > 4.0 then
  begin
    if (WaitForSingleObject(Event0,10) = WAIT_OBJECT_0) then
    begin

      pr_StartTimer(tp2);
      ccc:=0;
      repeat
        s1:= 'mainThread 2 Sekunden Arbeit '+__s(ccc);
        label1.Caption := s1;
        label1.refresh;
        inc(ccc);
      until fn_GetTimerSec(tp2) > 2.0;

      pr_StartTimer(tp1);
      s1:= 'mainThread idle';
      SetEvent(Event0);
    end;

  end;

  inc(cc);
  label1.Caption := s1 + IntToStr(cc)+' ';
  label1.refresh;

  Timer1.Enabled:=TRUE;
end;
bzw.

Delphi-Quellcode:
//----------------------------------
procedure TThread_a.Execute;
//----------------------------------
var tp2,tp1: Int64;
    ccc: Integer;
begin
  inherited;
  pr_StartTimer(tp1);
  s1:= 'Thread_a idle ';
  cc:=0;
  pr_StartTimer(tp1);
  while TRUE do
  begin
    sleep(1);

    if Terminated then
    begin
      exit
    end

    if fn_GetTimerSec(tp1) > 4.0 then
    begin
      if WaitForSingleObject(Event0,10) = WAIT_OBJECT_0 then
      begin
        ccc:=0;
        pr_StartTimer(tp2);
        repeat
          s1:= 'Thread_a Event0, 2 Sekunden Arbeit ! '+__s(ccc);
          sleep(1);
          inc(ccc);
        until fn_GetTimerSec(tp2) > 2;
        s1:= 'Thread_a idle ';
        show;
        pr_StartTimer(tp1);
        SetEvent(Event0);
      end;
    end;
    inc(cc);
  end
end;
o Damit kommem alle im richtigen Moment mal dran, insbesondere eben auch der Hauptthread


Meine Abhilfe sieht jetzt so aus:

o Die Teilthreads, aber nicht der hauptthread, werden weiterhin mit CriticalSection voreinander geschützt
o Der HauptThread stellt seine Auswerte/Anzeigeroutine dem Thread per EreignisProzedur zur Verfügung

  auftObj.thread_messen.onMeasThreadProc := pr_ThreadProc; o Der Thread führt diese Routine per Synchronize() aus.

Delphi-Quellcode:
//----------------------------------------------------------------
procedure Tthread_messen.pr_SyncProc;
//----------------------------------------------------------------
begin
  onMeasThreadProc(self)
end;
Delphi-Quellcode:
   if assigned(onMeasThreadProc) then
    begin
      Synchronize(pr_SyncProc);
    end;
o Während der Ausführung kann kein Repaint oder Neuaufbau der Anzeigen erfolgen, da die Ereignisprozedur kein KeepWindowsAlive oder Sleep() enthält.
o Erst wenn die Auswerte/Anzeigeroutine komplett am Stück beendet ist, kommt der HauptThread zum Zuge. Dann ist alles Kritische aber schon erledigt.

Für weitere erhellende Kommentare bin ich selbstverständlich dankbar. Ansonsten scheint mein spezielles Problem durch diese Verfahrensweise gelöst zu sein.
Danke nochmals an Dani für die schnelle Reaktion.
Klasse Forum, klasse Seite !
  Mit Zitat antworten Zitat