Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Thread Problem


David - Mo 09.02.04 18:50
Titel: Thread Problem
Hallo,
ich habe ein kleines Probem. Ich versuche mich grad in Threads einzuarbeiten und leider stürzt mein Mini Programm immer ab.

Hier der Code:

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:
var
  ThreadID : THandle; 
  ThreadH : THandle;
  ThreadID2 : THandle;
  ThreadH2 : THandle;

procedure threadtest (Edit : TEdit); stdcall;
var a: integer;
begin
  for a:=0 to 5000 do
//    Edit.text := IntToStr(a);
    ShowMessage('Thread 1 fertig!');
    ThreadH:=0;
end;

procedure threadtest2 (Edit : TEdit); stdcall;
var a: integer;
begin
  for a:=0 to 1000 do
//    Edit.text:=IntToStr(a);
    ShowMessage('Thread 2 fertig!');
    ThreadH2:=0;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  ThreadH:=CreateThread(nil,0,@threadtest,Edit1,0,ThreadID);
  ThreadH2:=CreateThread(nil,0,@threadtest2,Edit1,0,ThreadID2);
end;


Mit einem Thread geht es, aber bei 2 kann ich es vergessen.

Jemand ne Ahnung was ich falsch gemacht habe?

Moderiert von user profile iconPeter Lustig: Code- durch Delphi-Tags ersetzt


patrick - Mo 09.02.04 19:02

irgendwie erstelle ich theads ganz anders :?

schau dir am besten mal das thread-tut von Luckie an:
http://www.luckie-online.de/tutorials/threads/threads_tutorial.pdf

so mach ich das immer:

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:
39:
40:
41:
42:
43:
44:
unit thread_unti1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls;

type
  TmyTThread = class(TThread)
   public
   procedure Execute; override;
end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public

  end;

var
  myt1,myt2:TmyTThread;
implementation

{$R *.dfm}

procedure TmyTThread.Execute;
var i:integer;
begin
///eine aktion
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  myt1.Create(false);
  myt2.Create(false);
end;


end.


David - Mo 09.02.04 19:05

Hallo patrick,
das Tutorial ist mir bekannt, es geht aber in eine etwas andere Richtung. Um Threads zu erstellen gibt es schon mehrere Möglichkeiten, diese ist jedoch für meine Situation die Beste.
Ich verstehe nur halt nicht, wieso er beim 2. erstellten Thread abstürtzt und beim 1. nicht.


MSCH - Mo 09.02.04 19:25

schätze mal, dass deine Initialisierung etwas daneben läuft. Deine Treads laufen erstmal unendlich, rufen unendlich eine Schleife auf und geben eine Dialog aus. Ob diese Funktion Threadsicher ist, wage ich zu bezweifeln und den Thread via :=0 zu terminieren (?) geht auch nicht. Da solltest du schon CloseHandle benutzen. Schau dir mal die Erläuterungen im SDK dazu an.
Das der erste funktioniert, ist Zufall (?).

grez
msch


David - Mo 09.02.04 19:36

ok, danke Euch beiden. Ich denke, ich bekomme das jetzt hin!


Delete - Mo 09.02.04 20:04

Kennen schon, aber nicht gelesen oder:
Thread-Tutorial hat folgendes geschrieben:

Zu beachten ist allerdings noch folgendes: Benutzt man BeginThread als Wrapper für die API-Funktion CreateThread,
so darf man nicht die Aufrufkonvetion stdcall für die Thread-Funktion benutzen. Grund: BeginThread benutzt eine
"Thread-Wrapper"-Funktion anstatt des wirklichen Einsprungspunktes. Diese Funktion ist als stdcall definiert, sie verschiebt
die Parameter auf den Stack und ruft dann die eigene Thread-Funktion auf.

[..]

In einem Delphi-Programm sollten sie nie die Funktion CreateThread direkt aufrufen. Benutzen sie stattdessen die
Funktion BeginThread. Grund: BeginThread kapselt zwar nur die API-Funktion CreateThread, setzt aber zusätzlich
noch die globale Variable IsMultiThread und macht somit den Heap thread-sicher.

Die Thread-Funktion sieht auch anders aus:

Delphi-Quelltext
1:
type TThreadFunc = function(Parameter: Pointer): Integer;                    

Aber das eigentliche Problem dürfte die Übergabe des Edits als Thread-Parameter sein. Wie man Parameter an Threads übergibt kannst du in den Demos zu meinem Tutorial sehen. Übergib einen Zeiger auf einen Record.
Und nimm mal statt ShowMessage, Messagebox (die API-Version). Die VCL ist nämlich nicht thread-safe.
Und was deine aukommentierte Edit-Zeile angeht, mach dich mal in meinem Tutorial über CriticalSections schlau.


Motzi - Mo 09.02.04 20:53

Also was den Parameter betrifft so ist der obige Code durchaus korrekt, schließlich sind in Delphi ja alle Objekte nur Zeiger, also entspricht das übergebene TEdit-Objekt durchaus dem Pointer-Parameter von TThreadFunc. Die Prozeduren sind zwar als stdcall deklariert, aber es sind eben Prozeduren und keine Funktionen wie TThreadFunc (aber das allein ist noch kein schwerwiegendes Problem).

Ich seh das Problem auch bei den VCL-Zugriffen und zwar sowohl bei ShowMessage als auch bei den Zugriffen auf das Edit. Und VCL-Zugriffe würde ich generell sicherheitshalber eher über Synchronize machen als mit CriticalSections, da mit Synchronize der Code im primären Thread ausgeführt wird, während man per CriticalSection zwar seine eigenen Zugriffe auf ein VCL-Control synchronisieren kann, aber was die VCL im Hintergrund macht kann man nicht kontrollieren...