Avatar billede js_delphi Nybegynder
17. september 2010 - 09:04 Der er 11 kommentarer og
1 løsning

Vil gerne have feedback paa min foerste traad.

Hej,

Jeg har for foerste gang programmeret en separat traad, og vil gerne have jeres feedback, om jeg nu har gjort alt korrekt :)

Det, den separate traad goer, er at kopiere filer fra A til B maksimum en gang i minuttet.
Naar jeg siger maksimum en gang i minuttet, er det fordi, jeg stopper og starter traaden fra min hovedtraad efter behov.

Her er selve traaden:

unit UnitCopyThread;

interface

uses
  Classes, Windows, SysUtils, UnitSettings, Forms;

type
  TCopyThread = class(TThread)
  private
  protected
    constructor Create(aSuspended: Bool);
    procedure Execute; override;
  end;

implementation

procedure TCopyThread.Execute;
var
  SearchRec: TSearchRec;
begin
  while not Terminated do
  begin
    if DirectoryExists(ExtractFilePath(Application.ExeName) + 'TempTests') then
    begin
      FindFirst(ExtractFilePath(Application.ExeName) + 'TempTests\' + '*.xml', faAnyFile+faReadOnly, SearchRec);
      if CopyFile(PChar(ExtractFilePath(Application.ExeName) + 'TempTests\' + SearchRec.Name), PChar(frmSettings.PathTest + '\' + SearchRec.Name), True) then
        DeleteFile(PChar(ExtractFilePath(Application.ExeName) + 'TempTests\' + SearchRec.Name));
      while FindNext(SearchRec) = 0 do
      begin
        if CopyFile(PChar(ExtractFilePath(Application.ExeName) + 'TempTests\' + SearchRec.Name), PChar(frmSettings.PathTest + '\' + SearchRec.Name), True) then
          DeleteFile(PChar(ExtractFilePath(Application.ExeName) + 'TempTests\' + SearchRec.Name));
      end;
    end;

    if DirectoryExists(ExtractFilePath(Application.ExeName) + 'TempBadTests') then
    begin
      FindFirst(ExtractFilePath(Application.ExeName) + 'TempBadTests\' + '*.xml', faAnyFile+faReadOnly, SearchRec);
      if CopyFile(PChar(ExtractFilePath(Application.ExeName) + 'TempBadTests\' + SearchRec.Name), PChar(frmSettings.PathBadTest + '\' + SearchRec.Name), True) then
        DeleteFile(PChar(ExtractFilePath(Application.ExeName) + 'TempBadTests\' + SearchRec.Name));
      while FindNext(SearchRec) = 0 do
      begin
        if CopyFile(PChar(ExtractFilePath(Application.ExeName) + 'TempBadTests\' + SearchRec.Name), PChar(frmSettings.PathBadTest + '\' + SearchRec.Name), True) then
          DeleteFile(PChar(ExtractFilePath(Application.ExeName) + 'TempBadTests\' + SearchRec.Name));
      end;
    end;

  FindClose(SearchRec);
  Sleep(60000); //Run thread maximum every xx ms.
  end;
end;

constructor TCopyThread.Create(aSuspended: Bool);
begin
  FreeOnTerminate := True;
  inherited Create(aSuspended);
end;
end.


Her starter jeg traaden fra min hoved unit (i FormShow event):
CopyThread := TCopyThread.Create(False); //Due to False Execute will be called immediately.

Her "pauser" jeg traaden fra min hoved unit:
CopyThread.Suspend;

Her "genstarter" jeg traaden fra min hoved unit:
CopyThread.Resume;

Her terminerer jeg traaden fra min hoved unit (i OnDestroy event):
CopyThread.Terminate;


Kom med jeres mening!
Avatar billede hrc Mester
17. september 2010 - 11:05 #1
Skal nok kigge lidt mere når jeg får tid.

Når du terminerer din tråd bør du køre WaitFor (freeOnTerminate skal være false) inden du frigiver den.

Desuden bør du køre en Resume før du terminater. Tråden kan ikke terminate hvis den sover.

Kan i øvrigt ikke anbefale FreeOnTerminate nogetsteds. Man bør stoppe og frigive alle trådene så man ikke løber ind i problemer når programmet skal lukkes.
Avatar billede hrc Mester
17. september 2010 - 11:31 #2
Har ikke testet det, men det er bedre det her.

Der er flere ting:
1. Brug ikke FreeOnTerminate
2. Send alle oplysninger til tråden, lad ikke tråden finde det i en form et eller andet sted. Derfor den modificerede constructor
3. Lad være med at gentage samme bid kode. Derfor DPath og SPath.
4. Lad alle løkker exite hvis tråden termineres.
5. Lad ikke tråden sove i et minut. I værste tilfælde skal programmet vente 1 minut inden det kan lukkes. Brug powernaps.

type
  TCopyThread = class(TThread)
  private
    fSourcePath: string;
    fDestPath: string;
  protected
    constructor Create(aSourcePath, aDestPath: string); reintroduce;
    procedure Execute; override;
  end;

procedure TCopyThread.Execute;
const
  PowerNap = 100; // ms
var
  WakeUp: cardinal;
  SPath, DPath: string;
  Found: boolean;
  SearchRec: TSearchRec;
begin
  while not Terminated do
  begin
    SPath := fSourcePath + 'TempTests\';
    DPath := fDestPath;
    if DirectoryExists(ExcludeTrailingPathDelimiter(SPath)) then
    begin
      Found := FindFirst(SPath + '*.xml', faAnyFile or faReadOnly, SearchRec) = 0;
      try
        while Found and not Terminated do
        begin
          if CopyFile(PChar(SPath + SearchRec.Name), PChar(DPath + SearchRec.Name), True) then
            DeleteFile(PChar(SPath + SearchRec.Name));
          Found := FindNext(SearchRec) = 0;
        end;
      finally
        FindClose(SearchRec);
      end;
    end;

    SPath := ExtractFilePath(Application.ExeName) + 'TempBadTests\';
    if DirectoryExists(ExcludeTrailingPathDelimiter(SPath)) then
    begin
      Found := FindFirst(SPath + '*.xml', faAnyFile or faReadOnly, SearchRec) = 0;
      try
        while Found and not Terminated do
        begin
          if CopyFile(PChar(SPath + SearchRec.Name), PChar(fDestPath + SearchRec.Name), True) then
            DeleteFile(PChar(SPath + SearchRec.Name));
          Found := FindNext(SearchRec) = 0;
        end;
      finally
        FindClose(SearchRec);
      end;
    end;

      WakeUp := GetTickCount + 60000;
      while not Terminated and (WakeUp < GetTickCount) do
      Sleep(PowerNap);
  end;
end;

constructor TCopyThread.Create(aSourcePath, aDestPath: string);
begin
  inherited Create(true);
  FreeOnTerminate := false;
  fSourcePath := IncludeTrailingPathDelimiter(aSourcePath);
  fDestPath := IncludeTrailingPathDelimiter(aDestPath);
    Resume;
end;
Avatar billede hrc Mester
17. september 2010 - 11:36 #3
Det er stort set som tidligere:

fCopyThread := TCopyThread.Create('c:\src','c:\dest');

Ved frigivelse er proceduren:
fCopyThread.Resume;
fCopyThread.Terminate;
fCopyThread.WaitFor;

Egentlig burde du have en tråd til hver af de to operationer du har. Det kan constructoren let laves om til at understøtte.

Grunden til jeg skriver fCopyThread er, at variablen antages at ligge i formens private-del. Så plejer man at smække et F foran.
Avatar billede hrc Mester
17. september 2010 - 11:42 #4
Så vil resultatet se sådan ud:

procedure TCopyThread.Execute;
const
  PowerNap = 100; // ms
var
  Found: boolean;
  WakeUp: cardinal;
  SearchRec: TSearchRec;
begin
  while not Terminated do
  begin
    if DirectoryExists(ExcludeTrailingPathDelimiter(fSourcePath)) then
    begin
      Found := FindFirst(fSourcePath + '*.xml', faAnyFile or faReadOnly, SearchRec) = 0;
      try
        while Found and not Terminated do
        begin
          if CopyFile(PChar(fSourcePath + SearchRec.Name), PChar(fDestPath + SearchRec.Name), True) then
            DeleteFile(PChar(fSourcePath + SearchRec.Name));
          Found := FindNext(SearchRec) = 0;
        end;
      finally
        FindClose(SearchRec);
      end;
    end;

      WakeUp := GetTickCount + 60000;
      while not Terminated and (WakeUp < GetTickCount) do
      Sleep(PowerNap);
  end;
end;

Trådene skulle så kaldes således:

fCopyThread1 := TCopyThread.Create('c:\src\'TempTests','c:\dest\OK');
fCopyThread2 := TCopyThread.Create('c:\src\'TempBadTests','c:\dest\Bad');


Ved frigivelse er proceduren:
fCopyThread1.Resume;
fCopyThread1.Terminate;
fCopyThread1.WaitFor;

fCopyThread2.Resume;
fCopyThread2.Terminate;
fCopyThread2.WaitFor;

Kan evt. lægges ind i en TThreadList..
Avatar billede js_delphi Nybegynder
17. september 2010 - 13:18 #5
Tak for det indtil videre!!

1:
Jeg faar en kompilerfejl i linien:
fCopyThread1 := TCopyThread.Create('c:\src\TempTests','c:\dest\OK');
om at boolean og string ikke er kompatible.
Jeg kan ikke se, hvorfor den forventer boolean.

2:
Hvad goer de 100ms PowerNap?

3:
Hvordan kan det vaere, du bruger boolean og ikke bool?

4:
Hvorfor mener du, at det er bedst med to traade til en simple opgave som denne? Bruger man ikke bare unoedig processorkraft paa at administrere disse?

5:
Hvad goer "reintroduce" i constructoren?

6:
Hvornaar saetter man "a" foran parametre?

Haaber ikke du har mistet modet :)
Avatar billede hrc Mester
17. september 2010 - 13:30 #6
ad. 1. Du har ikke vist snuppet den nye constructor.

ad. 2. De 100ms er de power naps tråden gør indtil der er gået et minut. Hvis du vælger at stoppe tråden så er den maksimale pause 100ms, ikke et helt minut.

ad. 3. Fordi boolean nu er det man bruger i Delphi

ad. 4. Logisk set så er det samme opgave med forskellige stier - og så kan man ligeså godt lave to tråde.

ad. 5. Så kan man ændre udseene på en constructor. Jeg skrotter parameteren om den skal suspende og fører de to stier over.

ad. 6. Man sætter a i parametrene for så kan du overalt i koden se at denne variabel er noget proceduren er blevet kaldt med. Det og f'et gør debugging meget lettere.
Avatar billede js_delphi Nybegynder
17. september 2010 - 14:01 #7
1:

Her er linien, der fejler:
FCopyThread1 := TCopyThread.Create('', '');
Parametrene er kun tomme strenge som test.

Saadan ser min traad ud:

unit UnitCopyThread;

interface

uses
  Classes, Windows, SysUtils;

type
  TCopyThread = class(TThread)
  private
    FSourcePath: string;
    FDestPath: string;
  protected
    constructor Create(aSourcePath, aDestPath: string); reintroduce;
    procedure Execute; override;
  end;

implementation

procedure TCopyThread.Execute;
const
  PowerNap = 100; //ms.
var
  Found: boolean;
  WakeUp: cardinal;
  SearchRec: TSearchRec;
begin
  while not Terminated do
  begin
    if DirectoryExists(ExcludeTrailingPathDelimiter(FSourcePath)) then
    begin
      Found := FindFirst(FSourcePath + '*.xml', faAnyFile or faReadOnly, SearchRec) = 0;
      try
        while Found and not Terminated do
        begin
          if CopyFile(PChar(FSourcePath + SearchRec.Name), PChar(FDestPath + SearchRec.Name), True) then
            DeleteFile(PChar(FSourcePath + SearchRec.Name));
          Found := FindNext(SearchRec) = 0;
        end;
      finally
        FindClose(SearchRec);
      end;
    end;

    WakeUp := GetTickCount + 60000;
    while not Terminated and (WakeUp < GetTickCount) do
      Sleep(PowerNap);
  end;
end;

constructor TCopyThread.Create(aSourcePath, aDestPath: string);
begin
  inherited Create(True);
  FreeOnTerminate := False;
  FSourcePath := IncludeTrailingPathDelimiter(aSourcePath);
  FDestPath := IncludeTrailingPathDelimiter(aDestPath);
  Resume;
end;
end.

Jeg fatter det ikke, goer du??
Avatar billede js_delphi Nybegynder
17. september 2010 - 18:14 #8
Den modificerede constructor stod under protected, og da "default" constructoren forventer een boolean parameter, var det vidst logisk nok.
Nu staar den under public, og det spiller.

Til mit punkt 3:
Jeg har altid brugt bool. Er det usaedvanligt, og er der noget forkert i det??

Til mit punkt 5:
Det ser ud til at virke uden "reintroduce", hvordan kan det vaere?

Laeg svar!

Mange tak for - som saedvanlig - gode forklaringer!!
Avatar billede hrc Mester
17. september 2010 - 19:12 #9
Godt det kom til at virke. Bool er "native" windows som stammer fra C-verdenen. I Delphi, eller rettere Pascal, har der altid været en boolean. Der er nok ikke stor forskel på de to, men boolean er altså det programmeringssproget blev født med.

Det er længe siden jeg har kigget på reintroduce. Den kom frem i Delphi 4 eller 5. Det den gjorde dengang var, at den fjernede en compileradvarsl. Siden har jeg bare brugt det. Måske er den faktisk blevet unødvendig (kan ikke lige slå op i hjælpen da jeg er ved at konvertere 10Gb tekster).
Avatar billede hrc Mester
17. september 2010 - 19:14 #10
Den manglende public i klassen driller mig jævnligt, men lige præcis så sjældent, at det ikke er det første jeg tænker på.
Avatar billede js_delphi Nybegynder
16. april 2011 - 12:49 #11
Mangler der ikke en "Free" efter WaitFor, da FreeOnTerminate = False?

fCopyThread1.Resume;
fCopyThread1.Terminate;
fCopyThread1.WaitFor;
//fCopyThread1.Free; ???
Avatar billede hrc Mester
16. april 2011 - 14:24 #12
Det ser det faktisk ud til den gør. Tænk jeg overså det for jeg sætter altid FreeOnTerminate = false da jeg ellers tit støder på fejl når programmet lukkes ned om ørene på tråden.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester