While-Schleife mit Wartezeit

MaxAPL

Mitglied
Hallo zusammen,

ich stehe gerade vor einem Problem mit einer while-Schleife. Das Java-Skript ist Teil eines Projektes mit der CFD-Software STAR CCM+.

Ziel ist es, zu testen, ob eine Datei im Ordner vorhanden ist, und wenn nicht, zu warten, bis die Datei vorhanden ist und dies bei jeder Iteration des Berechnungsprozesses.

Wenn die Datei bereits vorhanden ist, gibt es einige Anweisungen zu befolgen.

Mit dem obigen Code funktioniert das Makro so lange, bis sich der benötigte Code nicht im Ordner befindet, und dann wartet die Software auf die Datei

1705497909577.png

Wenn ich die benötigte Datei in den Ordner kopiere, sollte der Java-Code fortgesetzt werden und bei jeder Iteration denselben Prozess durchlaufen.

Das Problem ist, die "InterruptedException" zu setzen, um den Prozess innerhalb der For-Schleife fortzusetzen, wenn die benötigte Datei in den Ordner kopiert wird.


Der Code lautet wie folgt:
Java:
package macro;

import java.util.*;
import java.io.*;
import star.common.*;
import star.base.neo.*;
import star.energy.*;
import star.vis.*;


public class Exchange_Table_TimeStep_with_wait extends StarMacro {

  public void execute() {
    execute0();
  }

synchronized private void execute0() {

    Simulation simulation_0 = getActiveSimulation();

    double Time_step = 1.0;
    double Maximum_Physical_Time = 4.0;
    double n = Maximum_Physical_Time/Time_step;

    // Load the data (table)

        for (int i=0; i <= n-1; i++){
            
        // Get the file in the folder

        File f = new File("V:\\FOLDER\\Temperature_Grid1_"+i+".csv");

            while (!f.isFile())
            {
                try {
                wait();
                }
                catch (InterruptedException e){
                    e.printStackTrace();
                }
            }

            simulation_0.println("File available");

            FileTable fileTable_0 =

            (FileTable) simulation_0.getTableManager().createFromFile(resolvePath("Temperature_Grid1_"+i+".csv"));

            simulation_0.getSimulationIterator().run(1,true);

            simulation_0.println("Value of i is "+i);
            
            }
    }
 }

Vielen Dank im Voraus,
Max
 
Hier bin ich jetzt unsicher, was Du genau erreichen willst. Mit wait() hältst Du den Thread ja erst einmal komplett an und die Frage ist: an welcher Stelle möchtest Du denn den Thread wieder aufwecken? Es müsste dann ja an irgend einer Stelle auf der Instanz, auf der Du wait() aufgerufen hast, ein notify() aufgerufen werden (oder ein notifyAll() auf beliebigem Objekt).

Evtl. willst Du nur eine kurze Pause haben? Also statt wait() ein Thread.sleep(100) oder so - dann wartet der Thread 0,1 Sekunde und läuft dann weiter. Du kannst die Zeit natürlich anpassen.
 
Hallo @KonradN,

Danke für deine Antwort.

Ja genau, das hatte ich mehrmals in Forums gelesen, das mit den notify(). Bei mir würde nur ein Thread vorhanden sein. Das Problem für mich liegt darin, wie stelle ich dieser Thread ein.

Nein, keine Pause sondern warten bis die Datei im Ordner liegt, sodass die Anweisungen innerhlab der for-loop weiter geführt werden können,

Zunächst habe ich eine for-loop für jeden Zeitschritt meiner Simulation.

Für jeden Zeitschritt sollte zuerst überprüft, ob die benötige Datei im Ordner liegt.

Falls ja --> die folgenden Anweisungen folgen

Java:
simulation_0.println("File available");

            FileTable fileTable_0 =

            (FileTable) simulation_0.getTableManager().createFromFile(resolvePath("Temperature_Grid1_"+i+".csv"));

            simulation_0.getSimulationIterator().run(1,true);

            simulation_0.println("Value of i is "+i);

Falls nein --> warten bis die Datei im Ordner liegt, und dann wenn die vorhanden ist, die Anweisungen wie oben folgen.
 
keine Pause sondern warten bis die Datei im Ordner liegt, sodass die Anweisungen innerhlab der for-loop weiter geführt werden können,
Ja, das ginge auch anders. Aber das verkompliziert den Code etwas und ich weiss nicht, ob es wirklich zielführend ist.

Es gibt einen WatchService, mit dem Du das Filesystem überwachen kannst:

Über java.nio.FileService kannst Du ein WatchService erzeugen. Der Ablauf sollte so sein:
  • Du erzeugst eine Instanz von java.nio.FileService
  • Du erzeugst eine Instant von java.nio.Path von dem Verzeichnis, das Du überwachen willst
  • Du registrierst den WatchService über Path.register und gibst da mit an, was Du für Events haben willst. ENTRY_CREATE dürfte das dann vermutlich sein.
  • Du holst den WatchKey über WatchService.take()
  • Nun kannst Du Events abfragen (WatchKey.take() und nicht WatchKey.pollEvents()) - dann hast Du bei take() ein Event, das Du auswerten kannst.

Die Links zu der Dokumentation der jeweiligen Methoden habe ich jetzt nicht heraus gesucht. Das sollte aber kein Problem sein für Dich hoffe ich. Ansonsten einfach kurz melden und ich (oder jemand anderes) würde Dir den Weg erläutern.

Und evtl. noch den Hinweis: Wenn Du zeitnah informiert wirst, dann kann es sein:
  • dass die Datei noch gesperrt ist bei exklusivem Zugriff (unter Windows durchaus nicht unüblich)
  • dass die Datei noch nicht fertig geschrieben wurde und Du daher unvollständige Daten bekommst.
 
Okay, sieht komplexer aus als erwartet.

Ich habe gedacht, dass es ein einfacher Weg geben wurde, um von dieser Wait raus zu gehen und dann die weiter Anweisungen folgen.

Mit einem Thread wäre es nicht zu machen ? Insbesondere, wir können wir diese Thread einstellen mit dieser InterruptException?

Java:
catch (InterruptedException e){
                    e.printStackTrace();
                }

Ich möchte gern alles in den "synchronized private void execute0() " haben, wenne es machbar ist.
 
Du musst ja irgendwie zu der Information kommen, dass die Datei da ist. Das, was Du dazu machen musst, kannst Du natürlich in eine andere Klasse verlagern, aber es macht natürlich keinen Sinn, mit zwei Thread zu arbeiten, wenn Du einfach den Ablauf hast, dass Thread 1 den zweiten Thread startet und dann wartet und dann läuft der zweite Thread und wenn er fertig ist, weckt er Thread 1 und beendet sich. Dann kann der erste Thread auch gleich durch laufen.

Das würde nur Sinn machen, wenn Du z.B. mehrere Threads hast und Du die dann nur Synchronisieren willst. Dazu dienen die wait / notify Methoden in erster Linie.

Aber natürlich liesse sich sowas abbilden. So eine FileWatcher Klasse, die mehrere Dateien prüfen kann und die einen blockierenden Aufruf hinzu gefügt hat, könnte z.B. so aussehen (Das ist aber ein Schnellschuss. Ich habe da versucht, die Zugriffe, die synchronisiert sein müssen, zu synchronisieren. Aber ich habe da jetzt nicht wirklich viel Zeit hinein gesteckt):
Java:
package de.kneitzel;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class FileWatcher {

    private Thread fileWatcherThread;

    private volatile boolean shouldRun = true;

    private List<Path> pathsToWatch = new ArrayList<>();

    public void stop() {
        shouldRun = false;
    }

    public boolean isRunning() {
        return fileWatcherThread != null && fileWatcherThread.isAlive();
    }

    public void waitForPath(Path pathToWatch) {
        synchronized(pathsToWatch) {
            pathsToWatch.add(pathToWatch);
        }
        
        if (!isRunning()) {
            start();
        }
        try {
            synchronized(pathToWatch) {
                pathToWatch.wait();
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } catch (IllegalMonitorStateException ex) {
            ex.printStackTrace();
        }
    }

    private void start() {
        System.out.println("Starting FileWatcher Thread...");
        shouldRun = true;
        if (isRunning()) return;

        fileWatcherThread = new Thread(this::doWatch);
        fileWatcherThread.start();
    }

    private void doWatch() {
        while (shouldRun) {
            synchronized(pathsToWatch) {
                if (pathsToWatch.isEmpty()) return;

                Iterator<Path> iterator = pathsToWatch.iterator();
                while (iterator.hasNext()) {
                    Path path = iterator.next();

                    if (path.toFile().exists()) {
                        synchronized (path) {
                            path.notify();
                        }
                        iterator.remove();
                    }
                }
            }

            try {
                Thread.sleep(50);
            } catch (InterruptedException ex) {}
        }
    }
}

Ein möglicher Aufruf (damit habe ich einen schnellen Test gemacht):
Java:
        FileWatcher watcher = new FileWatcher();
        System.out.println("Waiting for /Users/konrad/test.txt");
        watcher.waitForPath(Paths.get("/Users/konrad/test.txt"));
        System.out.println("done waiting ...");

Aber noch einmal ganz deutlich: Wenn Du nur auf ein einziges File wartest, dann ist das viel zu komplex! Warte einfach in einer Schleife a.la.
Java:
while (!f.isFile()) {
    try {
        Thread.sleep(50);
    }
    catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Wenn Du das in eine Methode "waitForFile" packst, dann hast Du unter dem Strich das gleiche Verhalten. Mit der gegebenen Klasse hast Du nur einen Vorteil, wenn Du mehrere Threads hast, die so warten, weil dann nur ein Thread aktiv wartet und nicht alle.
 
Okay danke. Ja ich wollte eigentlich nur ein Prozess haben und sollte nur auf einziges File warten.
In den letzten Code, mit "Thread.sleep(50)" wartet den Prozess 50ms, aber ich weiß nicht wann den File im Ordner liegen würde.
 
Okay danke. Ja ich wollte eigentlich nur ein Prozess haben und sollte nur auf einziges File warten.
In den letzten Code, mit "Thread.sleep(50)" wartet den Prozess 50ms, aber ich weiß nicht wann den File im Ordner liegen würde.
Dazu hast Du ja eine while Schleife. Dieses Warten wird also so oft gemacht, wie notwendig. Und es gibt kein Timeout.

Das sleep dient nur, dass man eine unnötige Last vermeidet. Du kannst es prinzipiell auch einfach mit
while (!f.isFile()) {}
versuchen (nur testweise!)
Das wird funktionieren, aber Du solltest dann einmal schauen, wie die CPU belastet ist - sobald er wartet wird eine Core auf 100% gehen.

Daher so ein Sleep. Das ist übrigens eine Sache, die man als statische Methode in eine Klasse Threads / ThreadUtils machen kann, denn so ein Sleep braucht man doch hin und wieder mal.
 
Guten Tag,

Wenn Du nur auf ein einziges File wartest, dann ist das viel zu komplex! Warte einfach in einer Schleife a.la.
Java:
Code:
while (!f.isFile()) {
    try {
        Thread.sleep(50);
    }
    catch (InterruptedException e) {
        e.printStackTrace();
    }
}
Das ist eigentlich den Ziel. Jedoch funktionniert es nicht, da nach den 50 ms, wurde die Simulation gestoppt und wartet nicht bis die Datei im Ordner liegt.

Wie kann ich um das Problem gehen?
 
Das ist eher kein Problem mit dem Java Code (so dieser so ist wie angezeigt) sondern vermutlich eher ein Problem von der Simulationssoftware (Star ccm+?) Aber ich kenne diese Software nicht und die Dokumentation war jetzt so auf Anhieb auch nicht direkt online zu finden, daher kann ich Dir nicht weiterhelfen.

Was ich Dir sagen kann: Der Thread, der da in dieser Schleife ist, bleibt in der Schleife, bis die Datei da ist. Aber natürlich kann die Software auf anderen Threads weiter laufen und dann diverse Dinge machen incl. auch dem Abbruch der Simulation. Aber da ich die Software nicht kenne ist das schlicht etwas, das sein könnte.
 
Ich wünsche Dir viel Erfolg. Evtl. kannst Du mir auch die Dokumentation einmal zusenden (konrad (at) neitzel.de). Wenn ich das richtig gesehen habe auf einer Webseite, dann liegt die Dokumentation nach einer Installation mit auf dem System. Dann könnte ich auch einmal drüber schauen, ob ich diesbezüglich etwas sehe.
 
Update: ich hatte die for-Schleife für n=4 Dateien parametriert und hatte bereits 3 im Ordner. Daher nach den Import der neuen Datei im Ordner hatte die Simulation gestoppt. Ich habe dann n auf 8 gesetzt zum Testen und funktioniert wunderbar.

Noch vielen Dank für Ihre Unterstützung.
 

Neue Themen


Zurück
Oben