Metodo per attendere il termine di un processo

di il
8 risposte

Metodo per attendere il termine di un processo

Salve,

all'interno di in una procedura vorrei cancellare una cartella con dei files obsoleti e sostituirla con una cartella contenente dei files aggiornati:

TDirectory.Delete(OldFolder, True);
TDirectory.Move(NewFolder, OldFolder);

L'esecuzione di questo codice però genera l'errore "percorso già esistente", probabilmente perché Move viene eseguito prima che Delete abbia terminato il processo.

Come si può garantire che Move venga eseguito solo al termine di Delete?

Ale

8 Risposte

  • Re: Metodo per attendere il termine di un processo

    al.delphi ha scritto:


    L'esecuzione di questo codice però genera l'errore "percorso già esistente", probabilmente perché Move viene eseguito prima che Delete abbia terminato il processo.
    Mi pare piuttosto strano che accada quanto dici: hai provato a mettere un breakpoint sulla riga della chiamata a Move() per vedere se al momento dell'arresto dell'esecuzione la cartella è stata rimossa?

    Prova inoltre a indicare la struttura della tua directory e dei file che contiene a titolo esemplificativo per verificare qual è la situazione in cui ti trovi e che parametri stai passando.

    Ciao!
  • Re: Metodo per attendere il termine di un processo

    Ciao Alka,

    grazie per la tua indicazione. Ho inserito tra Delete e Move una TStringDynArray per raccogliere con _Str := TDirectory.GetDirectories(OldFolder) i nomi delle cartelle esistenti. Tramite breakpoint, nell'array la cartella eliminata risulta effettivamente non esistente. Non era quindi un problema di tempismo, ma del percorso di destinazione al quale mancava un elemento. Move si lamentava giustamente.

    Se mi permetti vorrei comunque chiederti un tuo parere riguardo la domanda in oggetto perché ogni tanto mi trovo che un processo viene inizializzato prima che termina il processo precedente. Hai un metodo preferito per garantire che il processo successivo parte solo quando quello precedente è terminato?

    Ale
  • Re: Metodo per attendere il termine di un processo

    al.delphi ha scritto:


    Se mi permetti vorrei comunque chiederti un tuo parere riguardo la domanda in oggetto perché ogni tanto mi trovo che un processo viene inizializzato prima che termina il processo precedente. Hai un metodo preferito per garantire che il processo successivo parte solo quando quello precedente è terminato?
    In genere, i metodi che avviano qualcosa di "asincrono", ossia che girano in background lasciando che il programma prosegua la propria esecuzione nel punto in cui avviene la chiamata, sono espressamente indicati, aggiungendo ad esempio ...Async in fondo al nome del metodo stesso o con altri espedienti (es. richiedendo una procedure/function anonima come parametro che funga da callback).

    Tutti gli altri casi non rientrano in questo gruppo e quindi vengono eseguiti in modo "sincrono", che è il default per la quasi totalità delle procedure, delle funzioni e dei metodi della RTL/VCL.

    Non esiste quindi un modo per garantire quanto chiedi, nel senso che non dovrebbe essere assolutamente mai necessario fare quel tipo di controlli, e nei casi specifici dove questo è espressamente previsto, la gestione dell'esito dell'operazione in background richiede espressamente un callback da invocare al termine dell'elaborazione.

    Magari prova a fare un esempio di situazione che "sfugge" al tuo controllo, giusto per cercare di capire cosa intendi di preciso.

    Ciao!
  • Re: Metodo per attendere il termine di un processo

    Un esempio semplice:
    begin
      pgbProc.Visible := True;
      lblProc.Caption := 'Delete destination folder';
      TDirectory.Delete(ProjectPath, True);
    end;
    Risultato: La ProgressBar e il Label appaiono solo dopo che la cartella è stata rimossa.

    Un esempio nel quale l'esatto mantenimento dell'ordine è vitale per il funzionamento: se verifico l'orientamento del testo su un'immagine (line code #1) per poi estrarrlo tramite OCR (line code #2), l'estrazione parte prima che la rotazione abbia finito e quindi il risultato è garbage.
    Questa particolare situazione si risolve con uno sleep di arbitraria durata facendo ritardare artificialmente il processo di estrazione, ma mi si alzano i peli davanti a una soluzione così grezza e poco elegante.

    Purtroppo non raramente mi trovo di dover garantire che una linea di codice venisse solo eseguita al termine della precedente. Essendo la nature e le circostanze di tali casi non sempre identiche, ti chiedevo se avevi qualche suggerimento.

    Ale
  • Re: Metodo per attendere il termine di un processo

    al.delphi ha scritto:


    Risultato: La ProgressBar e il Label appaiono solo dopo che la cartella è stata rimossa.
    Alt, questo è un problema diverso: quando vengono modificate la ProgressBar e la Label, i valori delle proprietà cambiano e come "effetto collaterale" viene segnalato a Windows che il contenuto visuale dei controlli non è più "corrente" (esiste un metodo Invalidate() per questa segnalazione), e pertanto deve essere aggiornato sullo schermo.

    Per fare questo, Windows invia un messaggio opportuno all'applicazione (tecnicamente, WM_PAINT) che ricevuto dal Form e inoltrato ai controlli, consente a questi di ridisegnare il proprio aspetto per riflettere le modifiche apportate.

    Tuttavia, il problema è che questo messaggio viene inviato all'applicazione e inserito nella relativa coda dei messaggi, quindi verrà di fatto gestito solo dopo che la directory è stata rimossa con l'istruzione che segue.

    Riepilogando, le operazioni di cui stiamo parlando avvengono tutte in modo sincrono, ma l'ordine è il seguente (lo scrivo in pseudocodice prendendo spunto dal tuo):
  • Re: Metodo per attendere il termine di un processo

    Grazie per la spiegazione, Marco! - Appena ho sotto mano un codice da rompicapo lo posto. : )

    Ale
  • Re: Metodo per attendere il termine di un processo

    Salve a tutti,
    non è sufficiente un Application.ProcessMessages, per fare in modo che barra e label siano aggiornate graficamente?
  • Re: Metodo per attendere il termine di un processo

    lunaoutrun ha scritto:


    non è sufficiente un Application.ProcessMessages, per fare in modo che barra e label siano aggiornate graficamente?
    Se stai eseguendo un ciclo, puoi richiamare questo metodo per fare sì che l'applicazione gestisca i messaggi in coda e quindi anche quelli relativi al refresh degli oggetti grafici.

    Tuttavia, non è una soluzione elegantissima: oltre a rallentare il ciclo in sé, poiché possono esservi molti messaggi da gestire nella coda prima di riprendere l'esecuzione del ciclo che tiene bloccato il programma, vi sono anche svariati scenari indesiderati che andrebbero gestiti, tipo la possibilità di chiudere il programma all'improvviso durante l'operazione, oppure eseguire di nuovo la stessa procedura; in breve, occorre gestire molto bene l'interfaccia per evitare l'esecuzione di comandi indesiderati da parte dell'utente.

    E' anche vero che una gestione simile sarebbe da attuare anche nel caso dell'uso di un sistema multithreading, ma con prestazioni ed efficienza migliori a livello generale.

    Ciao!
Devi accedere o registrarti per scrivere nel forum
8 risposte