Avatar billede js_delphi Nybegynder
08. november 2010 - 09:04 Der er 9 kommentarer og
1 løsning

Korrekt og sikker maade at stoppe flere threads?

Hej,

som diskuteret tidligere har jeg et program, som bruger flere instanser af en traad (dvs. flere traade af samme art creates).
Traadene kopiere forskellige filer fra hver sin mappe til en anden:

Traad 1:
Filer fra Mappe1 (lokal) til Mappe11 (netvaerk)

Traad 2:
Filer fra Mappe2 (lokal) til Mappe2233 (netvaerk)

Traad 3:
Filer fra Mappe3 (lokal) til Mappe2233 (netvaerk)

Hvis jeg nu fra min hovedtraad opretter nye filer i mapperne 1-3,
stopper jeg foerst alle tre traade, for at vaere sikker paa, de ikke kopierer noget, mens jeg opretter nye filer:

if FThread1 <> NIL then
  FThread1.Suspend;
if FThread2 <> NIL then
  FThread2.Suspend;
if FThread3 <> NIL then
  FThread3.Suspend;

Dette faar NOGEN GANGE en (eller flere?) af traadene til at smide en fejl, men ikke hver gang:

Thread-error: Access in denied (5)

Der ER rettigheder (og adgang) til alle mapper, saa kunne det vaere noget med, at traadene kolliderer?

Her er execute-delen af traadene:

procedure TCopyThread.Execute;
const
  PowerNap = 100; //ms.
var
  Found: Bool;
  WakeUp: cardinal;
  SearchRec: TSearchRec;
begin
  while not Terminated and not Suspended do
  begin
    if DirectoryExists(ExcludeTrailingPathDelimiter(FSourcePath)) and
      DirectoryExists(ExcludeTrailingPathDelimiter(FDestPath)) 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), False) then //False causes CopyFile to overwrite an existing file.
            if FDeleteAfterCopy then
              DeleteFile(PChar(FSourcePath + SearchRec.Name));
          Found := FindNext(SearchRec) = 0;
        end;
      finally
        FindClose(SearchRec);
      end;
    end;

    WakeUp := GetTickCount + FInterval; //Run maximum every xx ms.
    while not Terminated and (WakeUp > GetTickCount) do
      Sleep(PowerNap);
  end;
end;


Hvad goer jeg mon forkert??
Avatar billede hrc Mester
08. november 2010 - 09:55 #1
Måske skal du sikre dig at diskoperationerne er færdige før du suspender trådene? Noget lignende WaitFor når trådene skal terminere.

Du har også muligheden at lade trådene reagere på de ændringer der sker i katalogerne. Altså selv opdage når der kommer nye filer. Du sletter jo aldrig, vel?
Avatar billede js_delphi Nybegynder
08. november 2010 - 10:19 #2
Jeg sletter filerne, naar de er blevet kopieret.
Hvilke funktioner skal jeg kigge paa ang.
"Du har også muligheden at lade trådene reagere på de ændringer der sker i katalogerne."
Avatar billede hrc Mester
08. november 2010 - 10:36 #3
Jens Borrisholt lavede engang en klasse som gjorde det. Du kan også finde noget her:

http://www.delphipages.com/records.cfm?kw=notify+of+folder+change

Det kunne være interessant at se hvilken fil og operation tråden var i gang med da den frembragte fejlen. Det kunne måske være at den faktisk er ved at flytte den fil du er i gang med at lave, betydende at suspend ikke er helt OK. Jeg plejer at bruge suspended := true da jeg vistnok havde problemer med suspend og resume
Avatar billede martinlind Nybegynder
08. november 2010 - 19:35 #4
while Found and not Terminated do
( du burde nok også checke på suspended her )

Eller lave dine tråde om så de auto-free'er når de er færdige, og så evt. lade dem kopi'ere EN fil ad gangen.
Avatar billede js_delphi Nybegynder
14. november 2010 - 09:23 #5
Jeg har implementeret forskellige aendringer, men venter lige med at berette, til jeg er sikker paa, det koerer stabilt.
Avatar billede js_delphi Nybegynder
22. november 2010 - 18:23 #6
Skummelt med de traade!
Fejlen ser ud til at komme, naar netvaerket et oejeblik ikke er tilgaengeligt. Det ved jeg kan ske, hvilket ogsaa er derfor jeg har valgt at laegge kopieringen separat, saa der bare forsoeges igen senere ved fejl.
At det saa resulterede i en fejlmelding, var jo ikke meningen.

>>while Found and not Terminated do
>>( du burde nok også checke på suspended her )

Det fjernede ikke fejlen, men jeg implementerede det alligevel, tak.

Det, som ser ud til at virke er at kapsle hele baduljen ind i en try/except:

procedure TCopyThread.Execute;
const
  PowerNap = 100; //ms.
var
  Found: Bool;
  WakeUp: Cardinal;
  SearchRec: TSearchRec;
begin
  while not Terminated and not Suspended do
  begin
    try
      Found := (FindFirst(FSourcePath + '*' + FFileExtension, faAnyFile or faReadOnly, SearchRec) = 0); //Check if any new files to be copied.
      try
        if Found then
          if DirectoryExists(GetDestPath(FSourcePath + SearchRec.Name)) then
            while Found and not Terminated and not Suspended do
            begin
              if CopyFile(PChar(FSourcePath + SearchRec.Name), PChar(IncludeTrailingPathDelimiter(GetDestPath(FSourcePath + SearchRec.Name)) + SearchRec.Name), False) then //False causes CopyFile to overwrite an existing file.
                if FDeleteAfterCopy then
                begin
                  //Delete file and header file:
                  if DeleteFile(PChar(FSourcePath + SearchRec.Name)) then
                    DeleteFile(PChar(FSourcePath + StringReplace(SearchRec.Name, ExtractFileExt(SearchRec.Name), '.h', [])));
                end;
              Found := (FindNext(SearchRec) = 0);
            end;
      finally
        FindClose(SearchRec);
      end;
    except
      ;//Exceptions are ignored.
    end;

    WakeUp := GetTickCount + FInterval; //Run maximum every xx ms.
      while not Terminated and (WakeUp > GetTickCount) do
        Sleep(PowerNap);

  end;
end;


Jeg troede egentlig at try/finally ogsaa opfangede exceptions, men jeg er blevet klogere.

Ioevrigt maatte jeg aendre min procedure for at stoppe traadene, da de froes, hvis jeg suspendede dem to gange!!:

procedure TfrmMain.StopThreads();
begin
  if (FCopyThreadLogs <> NIL) and not FCopyThreadLogs.Suspended then
    FCopyThreadLogs.Suspend;
  if (FCopyThreadTests <> NIL) and not FCopyThreadTests.Suspended then
    FCopyThreadTests.Suspend;
  if (FMergeThreadMonitorLogs <> NIL) and not FMergeThreadMonitorLogs.Suspended then
    FMergeThreadMonitorLogs.Suspend;
end;


Spoergsmaal:
Kan man altid regne med at try/except opfanger en exception, selv hvis fejlen opstaar i en kaldt procedure (hvor kaldet er placeret i try/except, men ingen try/except i selve den kaldte procedure)?
Avatar billede martinlind Nybegynder
23. november 2010 - 00:47 #7
ja den bliver fanget i "den første try except", og ja try finnaly fanger ikke fejl, men sikre at finally koden bliver kørt
Avatar billede js_delphi Nybegynder
08. december 2010 - 06:08 #8
Det ser ud til at spille.
Laeg svar begge to.
Tak for jeres kommentarer!
Avatar billede martinlind Nybegynder
08. december 2010 - 08:56 #9
Svar
Avatar billede js_delphi Nybegynder
09. december 2010 - 10:00 #10
hrc??
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