Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Thread startet execute nicht (https://www.delphipraxis.net/174973-thread-startet-execute-nicht.html)

Murkas 22. Mai 2013 16:30

Delphi-Version: 7

Thread startet execute nicht
 
Hallo zusammen,

Ich befasse mich nun seit einiger Zeit mit Delphi und habe mich nun an Multithreading probiert. Das heist ich habe mir wie in diversen Anleitungen beschrieben eine neue TCheckThread Klasse von TThread abgeleitet und sie angepasst. Über das Hauptformular rufe ich nun meinen TCheckThread in 1 bis mehreren Instanzen mit verschiedenen Parametern über TCheckThread.Create auf. Genau dort kommt es zum Problem: Der Thread beginnt nicht zu arbeiten.

Hier ein paar Quellcode Ausschnitte

Code:
[...]
type
  TCheckThread = class(TThread)
  private
    Fstartcountarray:unit1.tcountarray;
    Fendstring:string;
    Freforgestringarray:unit1.treforgestringarray;
    Fthreaddone:boolean;
    Fresultstring:string;
    Fresultpoints:integer;
  protected
    function getstatname(statid:integer):string;
    function calcpoints(calcablestring:string):integer;
    procedure getbestreforgeid;
    procedure execute; override;
  public
    constructor Create(startcountarray:tcountarray; endstring:string; reforgestringarray:treforgestringarray);
    property threaddone:boolean read Fthreaddone write Fthreaddone;
    property resultstring:string read Fresultstring write Fresultstring;
    property resultpoints:integer read Fresultpoints write Fresultpoints;
  end;

implementation

constructor TCheckThread.Create(startcountarray:tcountarray; endstring:string; reforgestringarray:treforgestringarray);
var i:integer;
begin
  inherited Create(true);
  Fthreaddone:=false;
  for i:=0 to 15 do Fstartcountarray[i]:=startcountarray[i];
  Fendstring:=endstring;
  Fresultpoints:=0;
  freforgestringarray:=reforgestringarray;
  Freeonterminate:=false;
  self.Resume;
end;

[...]

procedure TCheckThread.execute;
begin
form1.Memo2.Lines.Add('getbestreforgeid starting');
getbestreforgeid;
end;

[...]
(Hinweis: getbestreforgeid: in dieser Prozedur wird der beste Wert zwischen Start- und Endwert ermittelt und in Fresultstring geschrieben. Am Ende wird Fthreaddone auf true gesetzt, sodass die Werte über das Hauptformular ausgelesen werden.)

Aufgerufen wird der Thread dann in einer andren Unit:

Code:
calcthread[q]:=tcheckthread.Create(countarray,endstring,reforgestringarray);
Der gesamte TCheckThread.execute wird vom Compiler weg optimiert, Ich habe schon einiges versucht, dazu aber keine Lösung gefunden. Hat irgendjemand eine Idee dazu?

Der schöne Günther 22. Mai 2013 16:38

AW: Thread startet execute nicht
 
Hallo und Herzlich Willkommen in den heiligen Hallen des Wissen und des Wahnsinns (oder so ähnlich).


Erst einmal Herzlichen Glückwunsch, direkt mit der TThread-Klasse zu arbeiten und nicht direkt die WinAPI-Aufrufe zu verwenden. Ich benutze mittlerweile nur noch TThreads und finde das viel komfortabler.

Jedoch:
  1. Nutze bitte nicht
    Delphi-Quellcode:
    Resume()
    um den im 'suspended' erstellten Thread zu starten. Nimm
    Delphi-Quellcode:
    Start()
    .
  2. Bitte packe den Code in (Delphi)(/Delphi)-Tags statt (Code)(/Code)
  3. Greife um Himmels Willen nicht aus dem Thread auf dein Formular zu! (Beispiel:
    Delphi-Quellcode:
    form1.Memo2.Lines.Add
    . Eine Notlösung wäre die
    Delphi-Quellcode:
    Synchronize
    -Methode eines TThread-Objekts aber das finde ich ehrlich gesagt auch unsauber. Ein Thread sollte sich mit der grafischen Oberfläche nicht befassen.
    Falls du eine Möglichkeit gesucht hast um überhaupt festzustellen, ob der Thread läuft, setze doch einfach einen Haltepunkt irgendwo in die
    Delphi-Quellcode:
    Execute
    -Methode.

DeddyH 22. Mai 2013 16:45

AW: Thread startet execute nicht
 
TThread.Start gibt es erst seit Delphi 2010 ;)

Der schöne Günther 22. Mai 2013 16:50

AW: Thread startet execute nicht
 
Bitter, ich hätte es jetzt darauf geschoben.

Die Execute-Methode überschreibt die Methode aus TThread und erstellt wird auch ein TCheckThread-Objekt, da ist alles im Grünen.

Vielleicht fliegt die Methode nach dem VCL-Zugriff komplett raus? Aber dann sollte der Debugger wenigstens eine Exception anzeigen...

mjustin 22. Mai 2013 16:55

AW: Thread startet execute nicht
 
Zitat:

Zitat von Murkas (Beitrag 1216084)
Code:

constructor TCheckThread.Create(startcountarray:tcountarray; endstring:string; reforgestringarray:treforgestringarray);
var i:integer;
begin
  inherited Create(true);
  ...
  Self.Resume;
end;

Einfacher und kürzer ist es den Thread von Anfang an nicht Suspended zu starten:

Code:
constructor TCheckThread.Create(startcountarray:tcountarray; endstring:string; reforgestringarray:treforgestringarray);
var i:integer;
begin
  inherited Create(False);
  ...
end;
p.s. möglicherweise ist damit das Problem auch bereits behoben...

(ab Delphi 6 wird der Thread erst gestartet nachdem der Konstruktor ausgeführt wurde)

Ginko 22. Mai 2013 16:55

AW: Thread startet execute nicht
 
Ist das Self.Resume im Konstruktor so in Ordung ?

Hier gibt es auch noch ein Tutorial wo mit Synchronize auf die Oberfläche zugegriffen wird.
Sollte mit Delphi genauso laufen.
http://wiki.freepascal.org/Multithre...on_Tutorial/de

Mfg Ginko

Murkas 22. Mai 2013 17:29

AW: Thread startet execute nicht
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1216085)
Nutze bitte nicht
Delphi-Quellcode:
Resume()
um den im 'suspended' erstellten Thread zu starten. Nimm
Delphi-Quellcode:
Start()
.

Gibt es, wie schon erwähnt, in Delphi 7 noch nicht.

Zitat:

Zitat von Der schöne Günther (Beitrag 1216085)
Bitte packe den Code in (Delphi)(/Delphi)-Tags statt (Code)(/Code)

Ich werds mir merken, erschien mir in der Auswahl am passenden.
Zitat:

Zitat von Der schöne Günther (Beitrag 1216085)
Greife um Himmels Willen nicht aus dem Thread auf dein Formular zu! (Beispiel:
Delphi-Quellcode:
form1.Memo2.Lines.Add
. Eine Notlösung wäre die
Delphi-Quellcode:
Synchronize
-Methode eines TThread-Objekts aber das finde ich ehrlich gesagt auch unsauber. Ein Thread sollte sich mit der grafischen Oberfläche nicht befassen.
Falls du eine Möglichkeit gesucht hast um überhaupt festzustellen, ob der Thread läuft, setze doch einfach einen Haltepunkt irgendwo in die
Delphi-Quellcode:
Execute
-Methode.

Ja, dies ist tatsächlich nur dazu gewesen, dass ich sehe, was wirklich passiert und was nicht.

Die jetzt erwähnten Lösungsvorschläge führen aber auch alle nicht zum gewünschten Ergebnis. Es kommt nicht dazu, dass der Thread gestartet wird. Die gesammte TCheckThread.execute wird vom Compiler weg optimiert.

mjustin 22. Mai 2013 17:59

AW: Thread startet execute nicht
 
Zitat:

Zitat von Murkas (Beitrag 1216097)
Die jetzt erwähnten Lösungsvorschläge führen aber auch alle nicht zum gewünschten Ergebnis. Es kommt nicht dazu, dass der Thread gestartet wird. Die gesammte TCheckThread.execute wird vom Compiler weg optimiert.

Wird

Delphi-Quellcode:
calcthread[q]:=tcheckthread.Create(countarray,endstring,reforgestringarray);
denn erreicht und ausgeführt, oder ist da auch kein blauer Punkt?

Murkas 22. Mai 2013 18:24

AW: Thread startet execute nicht
 
ja, das wird definitiv erreicht und ausgeführt. Habe kurz davor einen Haltepunkt gesetzt und mir den Ablauf angeschaut. Auch die constructor-Prozedur wird komplett durchlaufen, blos die execute-Prozedur wird nicht gestartet.

Blup 23. Mai 2013 08:42

AW: Thread startet execute nicht
 
Zitat:

Zitat von Murkas (Beitrag 1216084)
Der gesamte TCheckThread.execute wird vom Compiler weg optimiert, Ich habe schon einiges versucht, dazu aber keine Lösung gefunden.

Da es sich um eine virtuelle Methode handelt, kann der Compiler gar nicht wissen ob diese zur Laufzeit verwendet wird oder nicht.
Deshalb kann diese auch eigentlich nicht wegoptimiert werden.

Gründe die mir einfallen:
- Der gepostete Quelltext stimmt mit dem tatsächlichen nicht überein und das "override;" wurde bei der Deklaration von "Execute" vergessen.
- Die Unit gehört nicht zu dem Projekt und wird deshalb nicht mehr compiliert, statt dessen wird eine alte "*.dcu" eingebunden.

Unabhängig vom aktuellen Problem sind mir die Property aufgefallen.
Der Zugriff auf Variablen aus mehreren Threads muss auf jeden Fall synchronisiert werden (z.B. Get- und Setmethoden mit TCriticalSection).

Murkas 23. Mai 2013 18:35

AW: Thread startet execute nicht
 
Also wirklich helfen tut davon nichts. Ich poste mal etwas mehr Quelltext (1:1 aus Delphi kopiert):

(Im übrigen weis ich, dass sicherlich das ein oder andere etwas anders aussehen müsste oder sollte, darum kümmere Ich mich aber, wenn es vom Prinzip her erstmal läuft)

Hier die procedure, die die Threads erzeugen müsste:
Delphi-Quellcode:
procedure getbestreforgeid(reforgestringarray:treforgestringarray);
var q:integer;
    startstring:string;
    endstring:string;
    countarray:tcountarray;
    oldpoints:integer;
    oldresult:string;
    calcthread:array[0..8] of TCheckthread;
    threaddone:array[0..8] of boolean;
    threadcount:integer;
    btimecount:integer;
label threadstartingdone;
begin
btimecount:=gettickcount;
oldresult:='00000000000000000000000000000000';
oldpoints:=0;
for q:=0 to cpucount do threaddone[q]:=true;
form1.Memo2.Lines.Clear;
form1.ProgressBar1.Max:=(length(reforgestringarray[0]))*(length(reforgestringarray[1]))*(length(reforgestringarray[2]))*(length(reforgestringarray[3]));
form1.ProgressBar1.Position:=0;
threadcount:=0;
form1.label21.caption:='threads: '+inttostr(threadcount)+'/'+inttostr(cpucount);
application.ProcessMessages;
countarray[0]:=0;
while countarray[0]<length(reforgestringarray[0]) do begin
  countarray[1]:=0;
  while countarray[1]<length(reforgestringarray[1]) do begin
    countarray[2]:=0;
    while countarray[2]<length(reforgestringarray[2]) do begin
      countarray[3]:=0;
      while countarray[3]<length(reforgestringarray[3]) do begin
        startstring:='';
        endstring:='';
        for q:=4 to 15 do countarray[q]:=0;
        for q:=0 to 3 do endstring:=endstring+reforgestringarray[q][countarray[q]];
        for q:=4 to 15 do endstring:=endstring+reforgestringarray[q][length(reforgestringarray[q])-1];
        //for q:=0 to 15 do startstring:=startstring+reforgestringarray[q][countarray[q]];
        form1.Label22.Caption:=(floattostr((round((gettickcount-btimecount)/100))/10)+' seconds');
        btimecount:=gettickcount;


        if threadcount<cpucount then begin
          for q:=0 to cpucount-1 do begin
            if threaddone[q] then begin
              threaddone[q]:=false;
              form1.memo2.lines.add('thread '+inttostr(q+1)+' of '+inttostr(cpucount)+' starting with start: '+startstring+', end: '+endstring);
              calcthread[q]:=tcheckthread.Create(countarray,endstring,reforgestringarray);
              form1.memo2.lines.add('thread started says threadhandler');
              //calcthread[q].Resume;
              threadcount:=threadcount+1;
              form1.label21.caption:='threads: '+inttostr(threadcount)+'/'+inttostr(cpucount);
              application.ProcessMessages;
              Goto threadstartingdone;
            end;
          end;
          threadstartingdone:
        end;
        {if threadcount=cpucount then begin}
          {while threadcount=cpucount do begin}repeat
            //form1.memo2.lines.add('threadcount=cpucount2');
             for q:=0 to threadcount-1 do begin
              //if not calcthread[q].threaddone then form1.memo2.lines.add('thread '+inttostr(q+1)+' is not done');
              if calcthread[q].threaddone then begin
                if calcthread[q].resultpoints>oldpoints then begin
                  oldpoints:=calcthread[q].resultpoints;
                  oldresult:=calcthread[q].resultstring;
                  form1.Memo2.Lines.Add('new best result: '+inttostr(oldpoints));
                  form1.memo2.lines.add(' str:'+oldresult);
                end;
                threadcount:=threadcount-1;
                form1.label21.caption:='threads: '+inttostr(threadcount)+'/'+inttostr(cpucount);;
                threaddone[q]:=true;
                calcthread[q].Free;
                form1.ProgressBar1.Position:=form1.ProgressBar1.Position+1;
                form1.Label20.Caption:=floattostr((round((form1.ProgressBar1.Position/form1.ProgressBar1.Max)*1000))/10)+' %';
                form1.memo2.lines.add('thread '+inttostr(q+1)+' done');
                application.ProcessMessages;
              end;
            end;
            sleep(500);
          until threadcount<>cpucount;

         countarray[3]:=countarray[3]+1;
      end;
      countarray[2]:=countarray[2]+1;
    end;
    countarray[1]:=countarray[1]+1;
  end;
  countarray[0]:=countarray[0]+1;
end;
//showmessage('ending');
while threadcount>0 do begin
  //form1.memo2.lines.add('threadcount=cpucount2');
  for q:=0 to threadcount-1 do begin
    if calcthread[q].threaddone=false then form1.memo2.lines.add('thread '+inttostr(q)+' is not done');
    if calcthread[q].threaddone then begin
      if calcthread[q].resultpoints>oldpoints then begin
        oldpoints:=calcthread[q].resultpoints;
        oldresult:=calcthread[q].resultstring;
        form1.Memo2.Lines.Add('new best result: '+inttostr(oldpoints));
        form1.memo2.lines.add(' str:'+oldresult);
      end;
      threadcount:=threadcount-1;
      form1.label21.caption:='threads: '+inttostr(threadcount)+'/'+inttostr(cpucount);;
      threaddone[q]:=true;
      calcthread[q].Free;
      form1.ProgressBar1.Position:=form1.ProgressBar1.Position+1;
      form1.Label20.Caption:=floattostr((round((form1.ProgressBar1.Position/form1.ProgressBar1.Max)*1000))/10)+' %';
      form1.memo2.lines.add('thread '+inttostr(q+1)+' done');
      application.ProcessMessages;
    end;
  end;
  sleep(200);
end;
//showmessage('result: '+inttostr(oldpoints)+' string: '+oldresult);
unit3.form3.showreforgeresult(oldresult);
unit3.Form3.Visible:=true;
end;
Hier die Unit4 mit den Threads:
Delphi-Quellcode:
unit Unit4;

interface

uses
  SysUtils, Classes, unit1, ExtCtrls, dialogs;

//type
  //treforgestringarray=array[0..15] of array of string;
  {wowitem = record
    id: integer;
    name: string;
    icon: string;
    quality: integer;
    itemlvl: integer;
    gems: tstringlist;
    armor: integer;
    stamina: integer;
    intelligence: integer;
    strength: integer;
    agility: integer;
    hit: integer;
    expertise: integer;
    haste: integer;
    mastery: integer;
    crit:integer;
    dodge: integer;
    parry: integer;
    spirit: integer;
  end; }

type
  TCheckThread = class(TThread)
  private
    Fstartcountarray:unit1.tcountarray;
    Fendstring:string;
    Freforgestringarray:unit1.treforgestringarray;
    Fthreaddone:boolean;
    Fresultstring:string;
    Fresultpoints:integer;
  protected
    function getstatname(statid:integer):string;
    function calcpoints(calcablestring:string):integer;
    procedure getbestreforgeid;
    procedure execute; override;
  public
    constructor Create(startcountarray:tcountarray; endstring:string; reforgestringarray:treforgestringarray);
    property threaddone:boolean read Fthreaddone write Fthreaddone;
    property resultstring:string read Fresultstring write Fresultstring;
    property resultpoints:integer read Fresultpoints write Fresultpoints;

  end;

implementation

constructor TCheckThread.Create(startcountarray:tcountarray; endstring:string; reforgestringarray:treforgestringarray);
var i:integer;
begin
  inherited Create(true);
  Fthreaddone:=false;
  for i:=0 to 15 do Fstartcountarray[i]:=startcountarray[i];
  Fendstring:=endstring;
  Fresultpoints:=0;
  freforgestringarray:=reforgestringarray;
  Freeonterminate:=false;
  Resume;
  //showmessage('thread');
  //self.Execute;
end;

function TCheckThread.getstatname(statid:integer):string;
begin
result:='';
if statid=1 then result:='Hit';
if statid=2 then result:='Expertise';
if statid=3 then result:='Haste';
if statid=4 then result:='Mastery';
if statid=5 then result:='Crit';
if statid=6 then result:='Dodge';
if statid=7 then result:='Parry';
if statid=8 then result:='Spirit';
end;

function TCheckThread.calcpoints(calcablestring:string):integer;
var calcedstats:wowitem;
    statvalue:integer;
    calcitemarray: array[0..15] of wowitem;
    i:integer;
begin
result:=0;
for i:=0 to 15 do begin
  calcitemarray[i]:=unit1.wowitemarray[i];
  statvalue:=0;
  if (calcablestring[2*i+1]='1')then begin
    statvalue:=round(calcitemarray[i].hit*0.4);
    calcitemarray[i].hit:=calcitemarray[i].hit-statvalue;
  end;
  if (calcablestring[2*i+1]='2')then begin
    statvalue:=round(calcitemarray[i].expertise*0.4);
    calcitemarray[i].expertise:=round(calcitemarray[i].expertise*0.6);
  end;
  if (calcablestring[2*i+1]='3')then begin
    statvalue:=round(calcitemarray[i].haste*0.4);
    calcitemarray[i].haste:=round(calcitemarray[i].haste*0.6);
  end;
  if (calcablestring[2*i+1]='4')then begin
    statvalue:=round(calcitemarray[i].mastery*0.4);
    calcitemarray[i].mastery:=round(calcitemarray[i].mastery*0.6);
  end;
  if (calcablestring[2*i+1]='5')then begin
    statvalue:=round(calcitemarray[i].crit*0.4);
    calcitemarray[i].crit:=round(calcitemarray[i].crit*0.6);
  end;
  if (calcablestring[2*i+1]='6')then begin
    statvalue:=round(calcitemarray[i].dodge*0.4);
    calcitemarray[i].dodge:=round(calcitemarray[i].dodge*0.6);
  end;
  if (calcablestring[2*i+1]='7')then begin
    statvalue:=round(calcitemarray[i].parry*0.4);
    calcitemarray[i].parry:=round(calcitemarray[i].parry*0.6);
  end;
  if (calcablestring[2*i+1]='8')then begin
    statvalue:=round(calcitemarray[i].spirit*0.4);
    calcitemarray[i].spirit:=round(calcitemarray[i].spirit*0.6);
  end;
  if (calcablestring[2*i+2]='1')then calcitemarray[i].hit:=calcitemarray[i].hit+statvalue;
  if (calcablestring[2*i+2]='2')then calcitemarray[i].expertise:=calcitemarray[i].expertise+statvalue;
  if (calcablestring[2*i+2]='3')then calcitemarray[i].haste:=calcitemarray[i].haste+statvalue;
  if (calcablestring[2*i+2]='4')then calcitemarray[i].mastery:=calcitemarray[i].mastery+statvalue;
  if (calcablestring[2*i+2]='5')then calcitemarray[i].crit:=calcitemarray[i].crit+statvalue;
  if (calcablestring[2*i+2]='6')then calcitemarray[i].dodge:=calcitemarray[i].dodge+statvalue;
  if (calcablestring[2*i+2]='7')then calcitemarray[i].parry:=calcitemarray[i].parry+statvalue;
  if (calcablestring[2*i+2]='8')then calcitemarray[i].spirit:=calcitemarray[i].spirit+statvalue;
end;

calcedstats:=extrastats;
for i:=0 to 15 do begin
  calcedstats.hit:=calcedstats.hit+calcitemarray[i].hit;
  calcedstats.expertise:=calcedstats.expertise+calcitemarray[i].expertise;
  calcedstats.haste:=calcedstats.haste+calcitemarray[i].haste;
  calcedstats.mastery:=calcedstats.mastery+calcitemarray[i].mastery;
  calcedstats.crit:=calcedstats.crit+calcitemarray[i].crit;
  calcedstats.dodge:=calcedstats.dodge+calcitemarray[i].dodge;
  calcedstats.parry:=calcedstats.parry+calcitemarray[i].parry;
  calcedstats.spirit:=calcedstats.spirit+calcitemarray[i].spirit;
end;
if calcedstats.hit<strtoint(form1.Edit1.Text) then exit;
if calcedstats.expertise<strtoint(form1.Edit2.Text) then exit;
if calcedstats.haste<strtoint(form1.Edit3.Text) then exit;
if calcedstats.mastery<strtoint(form1.Edit4.Text) then exit;
if calcedstats.crit<strtoint(form1.Edit5.Text) then exit;
if calcedstats.spirit<strtoint(form1.Edit6.Text) then exit;
if calcedstats.dodge<strtoint(form1.Edit7.Text) then exit;
if calcedstats.parry<strtoint(form1.Edit8.Text) then exit;

if form1.ListBox1.items.IndexOf(getstatname(1))<>-1 then result:=result+calcedstats.hit*(form1.listbox1.Items.count-form1.ListBox1.Items.IndexOf(getstatname(1)));
if form1.ListBox1.items.IndexOf(getstatname(2))<>-1 then result:=result+calcedstats.expertise*(form1.listbox1.Items.count-form1.ListBox1.Items.IndexOf(getstatname(2)));
if form1.ListBox1.items.IndexOf(getstatname(3))<>-1 then result:=result+calcedstats.haste*(form1.listbox1.Items.count-form1.ListBox1.Items.IndexOf(getstatname(3)));
if form1.ListBox1.items.IndexOf(getstatname(4))<>-1 then result:=result+calcedstats.mastery*(form1.listbox1.Items.count-form1.ListBox1.Items.IndexOf(getstatname(4)));
if form1.ListBox1.items.IndexOf(getstatname(5))<>-1 then result:=result+calcedstats.crit*(form1.listbox1.Items.count-form1.ListBox1.Items.IndexOf(getstatname(5)));
if form1.ListBox1.items.IndexOf(getstatname(6))<>-1 then result:=result+calcedstats.dodge*(form1.listbox1.Items.count-form1.ListBox1.Items.IndexOf(getstatname(6)));
if form1.ListBox1.items.IndexOf(getstatname(7))<>-1 then result:=result+calcedstats.parry*(form1.listbox1.Items.count-form1.ListBox1.Items.IndexOf(getstatname(7)));
if form1.ListBox1.items.IndexOf(getstatname(8))<>-1 then result:=result+calcedstats.spirit*(form1.listbox1.Items.count-form1.ListBox1.Items.IndexOf(getstatname(8)));

//if result>28000 then showmessage(calcablestring+' result:'+inttostr(result)+' hit:'+inttostr(calcedstats.hit)+' exp:'+inttostr(calcedstats.expertise)+' haste:'+inttostr(calcedstats.haste));
end;

procedure TCheckThread.getbestreforgeid;
var q:integer;
    currentstring:string;
    countarray:tcountarray;
    points:integer;
    oldpoints:integer;
    oldresult:string;
label startlabel;
label endlabel;
begin
form1.Memo2.Lines.Add('getbestreforgeid started');
countarray:=Fstartcountarray;
Goto startlabel;
countarray[0]:=0;
while countarray[0]<length(Freforgestringarray[0]) do begin
  countarray[1]:=0;
  while countarray[1]<length(Freforgestringarray[1]) do begin
    countarray[2]:=0;
    while countarray[2]<length(Freforgestringarray[2]) do begin
      countarray[3]:=0;
      while countarray[3]<length(Freforgestringarray[3]) do begin
         countarray[4]:=0;
        while countarray[4]<length(Freforgestringarray[4]) do begin
           countarray[5]:=0;
          while countarray[5]<length(Freforgestringarray[5]) do begin
             countarray[6]:=0;
            while countarray[6]<length(Freforgestringarray[6]) do begin
               countarray[7]:=0;
              while countarray[7]<length(Freforgestringarray[7]) do begin
                  countarray[8]:=0;
                while countarray[8]<length(Freforgestringarray[8]) do begin
                    countarray[9]:=0;
                  while countarray[9]<length(Freforgestringarray[9]) do begin
                      countarray[10]:=0;
                    while countarray[10]<length(Freforgestringarray[10]) do begin
                        countarray[11]:=0;
                      while countarray[11]<length(Freforgestringarray[11]) do begin
                           countarray[12]:=0;
                        while countarray[12]<length(Freforgestringarray[12]) do begin
                             countarray[13]:=0;
                          while countarray[13]<length(Freforgestringarray[13]) do begin
                               countarray[14]:=0;
                            while countarray[14]<length(Freforgestringarray[14]) do begin
                                 countarray[15]:=0;
                              while countarray[15]<length(Freforgestringarray[15]) do begin
                                startlabel:
                                currentstring:='';
                                for q:=0 to 15 do currentstring:=currentstring+Freforgestringarray[q][countarray[q]];
                                //showmessage(currentstring);
                                //memo2.Lines.Add(currentstring);
                                points:=calcpoints(currentstring);
                                if points>oldpoints then begin
                                  oldpoints:=points;
                                  oldresult:=currentstring;
                                end;
                                if currentstring=Fendstring then Goto endlabel;
                                form1.Memo2.Lines.Add('shortmessage');
                                    countarray[15]:=countarray[15]+1;
                                 end;
                                 countarray[14]:=countarray[14]+1;
                               end;
                               countarray[13]:=countarray[13]+1;
                             end;
                             countarray[12]:=countarray[12]+1;
                           end;
                           countarray[11]:=countarray[11]+1;
                        end;
                        countarray[10]:=countarray[10]+1;
                      end;
                    countarray[9]:=countarray[9]+1;
                    end;
                    countarray[8]:=countarray[8]+1;
                  end;
                  countarray[7]:=countarray[7]+1;
               end;
               countarray[6]:=countarray[6]+1;
             end;
             countarray[5]:=countarray[5]+1;
           end;
           countarray[4]:=countarray[4]+1;
         end;
         countarray[3]:=countarray[3]+1;
      end;
      countarray[2]:=countarray[2]+1;
    end;
    countarray[1]:=countarray[1]+1;
  end;
  countarray[0]:=countarray[0]+1;
end;
endlabel:
Fresultpoints:=oldpoints;
Fresultstring:=oldresult;
form1.Memo2.lines.Add('thread done says thread '+inttostr(Fresultpoints));
//showmessage('thread done says thread '+inttostr(Fresultpoints));
Fthreaddone:=true;
end;

procedure TCheckThread.execute;
begin
//Fresultpoints:=0;
//showmessage('thread started '+Fendstring);
getbestreforgeid;
form1.Memo2.Lines.Add('thread done says thread '+inttostr(Fresultpoints));
end;

end.

Blup 24. Mai 2013 14:19

AW: Thread startet execute nicht
 
Mein Delphi warnt, compiliert aber und hält am Breakpoint in der TCheckThread.execute-Methode an.
Code:
[DCC Warnung] Unit4.pas() H2365 Schreibweise der Überschreibe-Methode TCheckThread.execute muss exakt ihrem Vorfahren TThread.Execute entsprechen
Zitat:

Zitat von Murkas (Beitrag 1216235)
Also wirklich helfen tut davon nichts.

Was hast du den davon überprüft, ich bin weiterhin der Meinung das der Fehler in dieser Richtung zu suchen ist.

Die Struktur deiner Daten scheint mir für den Anwendungsfall ungeeignet.
Durch geschickte Optimierung könnte man den Ablauf sicher um den Faktor 100 beschleunigen.
Das ist sinnvoller als bei diesem Entwicklungsstand bereits auf Threads zu setzen.

Auf jeden Fall solltest du auf "Goto" verzichten.
Ein Vorschlag ohne jetzt zu viel zu verändern:
Delphi-Quellcode:
function TCheckThread.IncCountArray(var countarray: tcountarray) : Boolean;
var
  n: Integer;
begin
  for n := 15 downto 0 do
  begin
    countarray[n] := countarray[n] + 1;
    if countarray[n] < Length(Freforgestringarray[n]) then
    begin
      Result := True;
      Exit;
    end;
    countarray[n] := 0;
  end;
  Result := False;
end;

function TCheckThread.IsCountArrayValid(const countarray: tcountarray) : Boolean;
var
  n: Integer;
begin
  for n := 15 downto 0 do
  begin
    if countarray[n] >= Length(Freforgestringarray[n]) then
    begin
      Result := False;
      Exit;
    end;
  end;
  Result := True;
end;

procedure TCheckThread.getbestreforgeid;
var
  q:integer;
  currentstring:string;
  countarray:tcountarray;
  points:integer;
  oldpoints:integer;
  oldresult:string;
begin
  oldpoints := 0;
  oldresult := '00000000000000000000000000000000';

  countarray := Fstartcountarray;
  if IsCountArrayValid(countarray) then
  begin
    repeat

      currentstring:='';
      for q := 0 to 15 do
        currentstring := currentstring + Freforgestringarray[q][countarray[q]];
      //showmessage(currentstring);
      //memo2.Lines.Add(currentstring);
      points := calcpoints(currentstring);
      if oldpoints < points then
      begin
        oldpoints := points;
        oldresult := currentstring;
      end;
      if currentstring=Fendstring then
        Break;
      //form1.Memo2.Lines.Add('shortmessage');

    until not IncCountArray(countarray);
  end;

//form1.Memo2.lines.Add('thread done says thread '+inttostr(Fresultpoints));
//showmessage('thread done says thread '+inttostr(Fresultpoints));
  resultpoints := oldpoints;
  resultstring := oldresult;
end;

procedure TCheckThread.Execute;
begin
//Fresultpoints:=0;
//showmessage('thread started '+Fendstring);
  getbestreforgeid;
  threaddone:=true;
//form1.Memo2.Lines.Add('thread done says thread '+inttostr(Fresultpoints));
end;

Murkas 24. Mai 2013 15:11

AW: Thread startet execute nicht
 
Zitat:

Zitat von Blup (Beitrag 1216311)
Mein Delphi warnt, compiliert aber und hält am Breakpoint in der TCheckThread.execute-Methode an.
Code:
[DCC Warnung] Unit4.pas() H2365 Schreibweise der Überschreibe-Methode TCheckThread.execute muss exakt ihrem Vorfahren TThread.Execute entsprechen

Hm, also diese Warnung bekomme ich nicht. Liegt das einfach an der Groß-/Kleinschreibung?


Zitat:

Zitat von Blup (Beitrag 1216311)
Zitat:

Zitat von Murkas (Beitrag 1216235)
Also wirklich helfen tut davon nichts.

Was hast du den davon überprüft, ich bin weiterhin der Meinung das der Fehler in dieser Richtung zu suchen ist.

Also dass die TCheckThread.Execute das "override" enthält, ist ja in meinem geposteten Code zu lesen. Dann bleibt nurnoch, dass die Unit4 nicht eingebunden ist. Aber da sie sowohl unter den Project-Units angezeigt wird, als auch, dass die TCheckThread-Prozedur gefunden und ausgeführt wird, geh ich davon aus, dass sie eingebunden ist..

Zitat:

Zitat von Blup (Beitrag 1216311)
Die Struktur deiner Daten scheint mir für den Anwendungsfall ungeeignet.
Durch geschickte Optimierung könnte man den Ablauf sicher um den Faktor 100 beschleunigen.
Das ist sinnvoller als bei diesem Entwicklungsstand bereits auf Threads zu setzen.

Auf jeden Fall solltest du auf "Goto" verzichten.
Ein Vorschlag ohne jetzt zu viel zu verändern: (...)

Also vielen Dank dir erstmal, dass du dir so eine Mühe gemacht hast, ich werde mir deinen Code ansehen und wenn ich ihn verstanden habe gegebenenfalls verwenden. :) Leider löst das mein Problem immernoch nicht :(

Murkas 25. Mai 2013 20:36

AW: Thread startet execute nicht
 
Also..
Ich habe jetzt die Unit nochmal komplett aus dem Projekt gehauen und von Delphi ein neues Thread-Objekt erzeugen lassen, dem ich meine Prozeduren wieder hinzugefügt habe. Nur leider hat es nicht geholfen. Ich habe auch probiert mal keine eigene TCheckThread.Create Prozedur zu benutzen, sondern die von TThread. Alles kein Erfolg. Mir gehen so langsam die Ideen aus. Hat keiner mehr eine Idee?

sx2008 25. Mai 2013 21:54

AW: Thread startet execute nicht
 
Also dein Sourcecode ist noch sehr suboptimal.
Ich weiss nich ob es dir aufgefallen ist, aber dein Code besteht aus permanenten Wiederholungen.
Das Ganze wird sehr unübersichtlich und da nicht mal Kommentare vorhanden sind versteht man eigentlich nur "Bahnhof".
Guter Code soll aber selbsterklärend und ohne Wiederholungen sein.

Hier ein kleines Beispiel:
Delphi-Quellcode:
function TCheckThread.calcpoints(calcablestring:string):integer;
var calcedstats:wowitem;
    statvalue:integer;
    calcitemarray: array[0..15] of wowitem;
    i:integer;
begin
result:=0;
for i:=0 to 15 do begin
  calcitemarray[i]{*}:=unit1.wowitemarray[i];
  statvalue:=0;
  if (calcablestring[2*i+1]='1')then begin
    statvalue:=round(calcitemarray[i]{*}.hit*0.4);
    calcitemarray[i]{*}.hit:=calcitemarray[i]{*}.hit-statvalue;
  end;
Warum reitest du ständig auf
Delphi-Quellcode:
calcitemarray[i]
herum?
Verwendet eine einfache lokale Variable
Delphi-Quellcode:
var item:wowitem;
und die Sache wird schon klarer.
Du verwendest 16 Mal den Ausdruck
Delphi-Quellcode:
calcablestring[2*i+1]
; das tut doch in den Augen weh.
Auch hier: verwende eine lokale Zwischenvariable (Datentyp char)!

Deine Funktion/Methoden sind elendlang; sie passen nicht auf eine Seite und man muss ständig hoch und runterscrollen.
Halte deine Funktionen kurz und verwende Unterfunktionen!

Wenn du diese beiden Regeln beachtest kannst du deinen Code deutlich verbessern.

Murkas 25. Mai 2013 22:04

AW: Thread startet execute nicht
 
Also ich finde es ja sehr hilfreich, dass ihr versucht mir zu helfen, meinen Code zu verbessern, aber ich würde gerne erst einmal Alles zum laufen zu bringen, bevor ich zu optimieren beginne. Würde es euch denn helfen mein aktuelles Problem zu lösen, wenn ich meinen Code auskommentiere etc.?

Uwe Raabe 25. Mai 2013 22:16

AW: Thread startet execute nicht
 
Da du sagst, das Execute wird gar nicht ausgeführt, kannst du den Code darin auch weglassen bzw. auf eine Art Platzhalter reduzieren. Damit fällt schon mal ein großer Verwirrfaktor raus.

sx2008 25. Mai 2013 22:24

AW: Thread startet execute nicht
 
Zitat:

Zitat von Murkas (Beitrag 1216384)
..aber ich würde gerne erst einmal Alles zum laufen zu bringen

Das ist halt nicht so einfach.
Dein Code sieht z.Zt. so aus
http://n0inf.2dmlimousin.com/wp-cont...ing_messy2.jpg
Ein falscher Draht und nix funktioniert.
Wie soll man so ein Wirrwarr zum laufen bringen?

Du darfst z.B. aus einem Thread heraus nicht direkt auf ein Formular zugreifen weil die VCL nicht threadsicher ist.
In deinem Code passiert das aber dutzende Male.

Murkas 25. Mai 2013 22:29

AW: Thread startet execute nicht
 
Wenn ich die TCheckthread.execute komplett raus kommentiere, dann bekomme ich eine EAbstractError Exception. Nehme ich den Code wieder rein, dann wird er nicht ausgeführt.

Im übrigen funktioniert es auch nicht, wenn ich sämtliche Zugriffe auf Formular 1 entferne. Ich weis aber auch, dass der Code in der TCheckthread.execute funktioniert, weil wenn ich diese Prozedur von Unit 1 ausführe, dann wird es zwar nicht als Thread ausgeführt, aber ich komme zu meinem Ergebnis.

Edit: Übrigens kann man das Bild nicht sehen @sx2008

Uwe Raabe 25. Mai 2013 22:47

AW: Thread startet execute nicht
 
Was genau bringt dich denn zu dem Schluss, daß Execute nicht ausgeführt wird?

Murkas 25. Mai 2013 22:56

AW: Thread startet execute nicht
 
Ich habe versucht über showmessage und über ein memo auf Form1 eine Nachricht anzuzeigen. Beides kommt nicht zu stande.

Mir ist aber dabei was Interessantes aufgefallen. Wenn ich den Code ändere, dann wird die execute in einigen, nicht einfach reproduzierbaren Fällen ausgeführt.

Sir Rufo 25. Mai 2013 23:14

AW: Thread startet execute nicht
 
Ein Zugriff aus dem Thread Kontext auf die VCL oder auch ShowMessage ist ein absolutes NoGo.

Sowas nur synchronisiert machen.

Zum Thema Threads solltest du dir ein paar Tutorials ansehen, denn das ist nicht trivial.

Murkas 25. Mai 2013 23:18

AW: Thread startet execute nicht
 
Ich habe mir schon einige durchgelesen, jedoch wüsste ich nicht, wie mir das Synchroniesieren hier helfen sollte. Und soo schwer sind Threads mit TThread ja nun auch nicht.. naja.. also wenn es denn dann funktioniert :?

DelTurbo 26. Mai 2013 03:41

AW: Thread startet execute nicht
 
Zitat:

Zitat von Sir Rufo (Beitrag 1216392)
Ein Zugriff aus dem Thread Kontext auf die VCL oder auch ShowMessage ist ein absolutes NoGo.

Damit hat er vollkommen recht. Das ist das erste was du ändern musst. Wenn nicht anders, mach eine Konsole mit rein, und arbeite mit WriteLn um auf die schnelle eine Ausgabe zu machen. Dann brauchst du, meines Wissens, erst mal nicht syncen.

Uwe Raabe 26. Mai 2013 08:04

AW: Thread startet execute nicht
 
Zitat:

Zitat von Murkas (Beitrag 1216391)
Ich habe versucht über showmessage und über ein memo auf Form1 eine Nachricht anzuzeigen. Beides kommt nicht zu stande.

Daraus kannst du aber nur schließen, daß die erwarteten Auswirkungen dieser beiden Aktionen nicht eingetreten sind. Das sagt überhaupt nichts darüber aus, ob das Execute ausgeführt wurde oder nicht. Der Titel führt als jeden, der dir helfen will, gewaltig in die Irre. Realistischer wäre: ShowMessage und Ändern von Memo-Inhalten funktionieren nicht im Thread.

Es ist hier schon mehrfach deutlich gemacht worden, daß Zugriffe auf die VCL (dazu gehört Showmessage und das Manipulieren eines Memos) aus einem Thread heraus nur eingeschränkt, wenn überhaupt, funktionieren. Deine Beobachtungen bestätigen das doch sehr anschaulich.

Wenn dir also schon mehrere Leute sagen, was du falsch machst, dann halte dich doch bitte zunächst mal an diese gut gemeinten Ratschläge!

Murkas 26. Mai 2013 13:05

AW: Thread startet execute nicht
 
Ok, ich denke ich habe nun verstanden, was mein Fehler ist. Ich habe einfach mal über die execute Prozedur eine synchronisierte Prozedur gestartet, die mir eine Nachricht anzeigt. Das heist, dass die execute doch gestartet wird. Ich hatte einfach die Auswirkung unterschätzt, die entsteht, wenn man etwas unsynchronisiert anzeigen möchte. Demzufolge wäre dann eine andere Threadüberschrift wirklich hilfreich gewesen, ich bin aber davon ausgegangen, dass die execute einfach nicht gestartet wird. Im Ergebnis muss ich also meinen Fehler im Quellcode des Threads suchen.

Eine andere Frage, die bei mir da grade so aufkommt, ist noch: Warum akzeptiert
Delphi-Quellcode:
synchronize()
keine Prozeduren mit Parametern?

DeddyH 26. Mai 2013 13:09

AW: Thread startet execute nicht
 
Weil TThreadMethod eine parameterlose Methode ist. Du kannst aber doch eine solche synchronisieren, innerhalb derer Du dann einfach eine Methode mit Parametern aufrufst.

[edit] Vielleicht war das jetzt etwas schwer verständlich, daher ein Beispiel:
Delphi-Quellcode:
...
Synchronize(Parameterlos);
...

procedure TDeinThread.Parameterlos;
begin
  MachIrgendwas(FPrivatesFeld1, FPrivatesFeld2);
end;

procedure TDeinThread.MachIrgendwas(Param1, Param2: integer);
begin
  //Code
end;
[/edit]


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:40 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz