Autor Beitrag
chubbson
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 32
Erhaltene Danke: 1



BeitragVerfasst: Mi 27.01.10 13:50 
Hallo
Ich habe ein problem mit Threads in einer DLL.
Ich starte mit einem LoadLib der mir meine DLL ladet eine Funktion aus der DLL die mir
~5 Threads in einem Threadpool laded und ausführen lässt.
Wenn ich über ein Abort die Threads beende werden alle threads solange im threadpool
geprüft bis diese beendet werden können. Sobald alle Threads beendet sind
ist der abort abgeschlossen. Soweit funktioniert alles einwandfrei.

Nun wenn ich die DLL aber lade und starte wieder alle 5 Threads am laufen sind und ich dann
direkt eine FreeLibrary ausführe, wird zwar die abort funktion ausgeführt die dann für
alle 5 threads ein terminate ausführt. danach werden alle 5 threads so lange geprüft nicht mit waitfor
sondern ende execute wird ein property isExecuted auf true gesetzt.
naja danach werden alle 5 threads so lange geloopt bis alle auf true sind.

Hier in dieser Schleife bleibt er manchal in einem Deadlock da irgendiwie nicht mehr alle Threads ausführen kann. sprich es sind noch nicht alle auf Excecuted und wenn ich den Breakpoint nur im Worker habe breakt er dort auch nicht mehr. aber der prozessor arbeitet weiterhin auf hochtouren.

Manchmal wird die isExecuted in einigen Threads auch auf true gesetzt obwohl ich einen breakpoint auf dem einzigen Aufruf habe ohne das er bei diesem breakpoint haltet.

Kann mir da jemand weiterhelfen. der Debugger müsste doch bei jedem thread in der Execute halten oder?
Ich schnippel mir gleich noch einige Code auszüge zusammen

Verwendet wird D7 und die dll wird gedebuggt.

abort funktion die darauf wartet bis alle threads beendet wurden...
die abort funktion läuft einwandfrei wenn man sie direkt aufruft.
Wenn sie über FreeLibrary aufgerufen wird tritt der oben beschriebene fehler auf
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
procedure THandler.Abort();
var
  worker: TWorker;
  i: Integer;
  allTerminated: Boolean;
  j, p: Integer;
begin
  if (HandlerState <> hsReady) then begin
    if (Assigned(Threads) and (Threads.Count > 0)) then begin

      //terminate threads
      for i:=Threads.Count-1 downto 0 do begin
        worker := TWorker(Threads[i]);
        worker.Terminate();
      end;

      //wait until alls threads are terminated
      repeat
        allTerminated := true;
        for i:=Threads.Count-1 downto 0 do begin
          worker := TWorker(Threads[i]);
          if not worker.IsExecuted then allTerminated := false;
        end;
      until (allTerminated);

      //free threads
      for i:=Threads.Count-1 downto 0 do begin
        worker := TWorker(Threads[i]);
        worker.Free();
        Threads.Delete(i);
      end;

    end;

    CleanQueue();
    HandlerState := hsReady;
  end;
end;


Der Worker Execute teil des Thread
Mancham kommt der Debuger gar nicht mehr in den Execute teil beim abort über freelibrary
im Try part werden noch funktionen einen anderen DLL aufgerufen! evtl da ein problem?
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TWorker.Execute;
begin
  try
    try
      // do Sth 
      // Funktionen einer weiteren dll werden aufgerufen
    except
      on E:Exception do begin
      end;
    end;
  finally
    FIsExecuted := true;
  end;
end;



Moderiert von user profile iconNarses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Mi 27.01.2010 um 13:37
Astat
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 75
Erhaltene Danke: 1

Windows 2000
D6, D7, D2007, Lazarus
BeitragVerfasst: Mi 27.01.10 14:30 
user profile iconchubbson hat folgendes geschrieben Zum zitierten Posting springen:
Wenn sie über FreeLibrary aufgerufen wird tritt der oben beschriebene fehler auf

Hallo chubbson, zeig doch mal den Entry der DLL.

Als Klassiker wird im DLL_PROCESS_DETACH mit einem WaitForMultipleObject alles aufgeräumt.
Die Abfrage nach dem Status der Threads in einer Schleife ist da etwas eigenartig.
Normalerweise verwendet man Sperrobjekte zum Signalling, dafür wurden diese gebaut.

lg. Astat

Moderiert von user profile iconNarses: Zitat kenntlich gemacht.
chubbson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 32
Erhaltene Danke: 1



BeitragVerfasst: Mi 27.01.10 14:40 
in der SubLib sind die Funktionen die dann im Thread oben aufgerufen werden.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
procedure LibraryProc(Reason: Integer);
begin
  case Reason of
    DLL_PROCESS_ATTACH: begin
      System.IsMultiThread := true;
      LoadSubLib();
    end;

    DLL_THREAD_ATTACH: begin
    end;

    DLL_THREAD_DETACH: begin
    end;
    
    DLL_PROCESS_DETACH: begin
      if Assigned(cHandler) then begin
        cHandler.Abort();
        cHandler.Free();
        FreeSubLib();
      end;
    end;
  end;

  if Assigned(DllProcNext) then
    DllProcNext(Reason);
end;
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Mi 27.01.10 14:43 
Zum Debuggen musst du die DLL "starten". Du benötigst die DLL als aktives Projekt und über Menü > Start > Parameter > Host-Anwendung musst du deine Anwendung angeben. Nur dann kannst du die innerhalb der DLL Debuggen. Ansonsten kannst du nur innerhalb deiner Anwendung debuggen.

Deine Schleife ist in der Tat etwas seltsam. Abgesehen davon betreibst du Busy-Waiting. Also du wartest in einer Endlosschleife mit 0 Verzögerung. Wenn du Glück hast und deine Threads in niedriger Priorität laufen bekommen die wärend der Schleife kaum noch rechenzeit und könnten sich so auch nicht beenden. Ich hoffe die Threads geben sich auch nicht selber frei. Also FreeOnTerminate muss in dem Fall false sein.

Bessere Lösung. Entweder nimmst du die Handles aller Threads und benutzt die Methode WaitForMultipleObject (wie Astat schon gesagt hat). Könntest du auch direkt anstelle der Schleife machen. Was auch gehen würde wäre du rufst Free der ThreadKlassen auf. Das Free ruft intern ein Wait (intern glaube ich WaitForSingleObject) auf und das wartet so lange bis der Thread geschlossen wurde. Dann ist der Thread auch definitv zu. Und du verbrauchst keine Rechenleistung beim Warten.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
chubbson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 32
Erhaltene Danke: 1



BeitragVerfasst: Mi 27.01.10 16:50 
Die DLL debuggen kann ich schon, da liegt nicht das problem.
Mein Problem liegt das wenn ich im Worker am Ende der Execute Procedure ein Breakpoint auf
FIsExecuted := true; setze das der debuger nur sporadisch dort anhält.
Bei manchen Threads wird das Flag Automatisch auf True gesetzt und bei manchen hält er beim Breakpoint.
Das ist es was mich am meisten Iritiert.


Hmm okay ich könnte auch ein sleep in die repeat schleife einbauen. Ich prüfe halt mein eigenes Flag ob dieses gesetzt wurde.

Ich habe nun auch
ausblenden Delphi-Quelltext
1:
WaitForMultipleObjects(Threads.Count, @Threads, true, 0 );					

anstatt der Schleife genommen. Jedoch hält er auch dort nur sporadisch beim worker Breakpoint.
'WaitForMultipleObjects' wird dann relativ schnell verlassen. Die IsExecuted properties sind da aber auch nicht überall auf true gesetzt.

Auch wenn ich die Threads mit Free freigebe, das wird weiter unten sowieso noch gemacht, werden die einzelnen Excecute methoden im Handler bis am schluss abgearbeitet.

Wie gesagt, das Problem habe ich nur wenn ich meine DLL mit FreeLibrary freigebe und dort meine Abort Funktion aufrufe. Wenn ich die Abort funktion zuerst aufrufe und danach erst Free Library funktioniert alles einwandfrei.