Dauerschleife unterbrechen mit sleep()

Status
Nicht offen für weitere Antworten.

brezn

Mitglied
Hallo Leute,

ich habe eine dauerschleife, die bestimmte aufgaben macht, bis irgendwann eine schaltervariable auf false gesetzt wird. sie sieht folgendermaßen aus:

Java:
while(an){
			... //Code der ausgeführt wird
			try{   
				Thread.sleep(schlagzeit); 
            }
            catch (Exception ex) {}

}

Die Variable an ist vom Typ boolean. Bekannterweiße gibt es ja einen stack overflow bei Dauerschleifen, also dachte ich mir, dass ich das ganze mit Thread.sleep() umgehen kann. Allerdings hängt sich auch hier das Programm auf. ist sleep() überhaupt die Lösung und wenn ja, was habe ich falsch gemacht?
wenn nein, welche anderen lösungen gibt es dann?
 
ein stackoverflow kommt nicht bei einer "endlos" bzw "dauerschleife" sondern "an application recurses too deeply"...

while(true) mit sleep ist immer zu ueberlegen (zb gegen notify und wait auszutauschen)
 
> Bekannterweiße gibt es ja einen stack overflow bei Dauerschleifen

nein

> dass ich das ganze mit Thread.sleep() umgehen kann

nein, wobei dir andere Dinge vielleicht helfen,
Thread.sleep() ermöglicht, weniger als 10 Milliarden Schleifendurchläufe pro Sekunde zu haben und 100% CPU-Belastung, auch nicht schlecht

> Allerdings hängt sich auch hier das Programm auf.

aus dem Code nicht zu erkennen, Thread.sleep() wird nicht alleine schuld sein

> ist sleep() überhaupt die Lösung

ohne genaue Problemstellung kaum zu beurteilen

> wenn ja, was habe ich falsch gemacht?

zumindest zuwenig erklärt/ kein vollständiger Code
 
Bekannterweiße gibt es ja einen stack overflow bei Dauerschleifen

Ist mir eigentlich nicht bekannt.

Allerdings hängt sich auch hier das Programm auf.

Das Programm wartet bei jedem Durchlauf
Code:
schlagzeit
Millisekunden

ist sleep() überhaupt die Lösung und wenn ja, was habe ich falsch gemacht?

Kommt drauf an, was du eigentlich machen willst und wo das Problem liegt 😛
 
manno man immer diese arbeitslosen Informatiker hier die alle zur selben Zeit das selbe antworten 😀
 
"Thread.sleep()" ist weder für den Stack-Overflow verantwortlich, noch kann dieser dadurch verhindert werden.
Innerhalb von "while(an)" muß sichergestellt sein, das "an" irgendwann "false" wird, auch bzw. vorallem bei rekursivem Aufruf. "an = false;" gehört deswegen noch unbedingt in den "catch"-Block von "Thread.sleep()". Falls "an" eine Instanzvariable ist, kann "an" auch von ausserhalb beeinflusst werden, z.B. mit "setAn(false);".
 
oh okay, ich dachte, meine erklärungen reichen aus, aber da hab ich mich wohl getäuscht ^^

also gut. sorry, ich meinte nicht stack overflow, sondern cpu auslastung. sprich, man sollte der cpu doch mit Thread.yield() luft zum atmen geben, oder? das ist doch der sinn von dieser yield methode oder täusch ich mich da?

so, also mit Thread.yield() funktioniert es auch nicht. darum erkläre ich kurz mein programm. ich bastel grade an einem metronom für musiker. da kann man ein tempo einstellen und taktart und das ganze dann ablaufen lassen. da gibt es eine methode, die heißt zaehlen, in der diese Dauerschleife ist, die so lange zählt, bis der Benutzer eben wieder auf Stop klickt.
Hier die Methode zaehlen:
Java:
public void zaehlen(){
		while(an){
			if(aktZahl>otakt) aktZahl=1;
			draw.ZahlZeichnen(aktZahl);
			aktZahl++;
			try{   
                Thread.sleep(schlagzeit);
				Thread.yield(); 
            }
            catch (Exception ex) {}

		}
	}
draw ist eine Referenz auf eine klasse, die für das Zeichnen der Zahlen zuständig ist. Ich zeichne quasi den aktuellen Schlag vom Takt auf die Benutzeroberfläche. Die Variable schlagzeit gibt quasi das Tempo an, das heißt, die Schleife soll je nach eingestelltem Tempo entsprechend warten.

So, ich hoffe, ihr könnt mir nun bissel besser helfen ^^
 
selbst eine leere Schleife läßt die CPU auf 100% laufen, wenn kein Sleep drin ist,
dann wird eben umso öfter die Schleifenvariable erhöht usw. bzw. gar nichts gemacht außer hin und her zu springen bei while (true)

-------

mit Thread.sleep() kann man das verlangsamen, korrekt,

es ist nun immer noch keine Frage/ kein Problem sichtbar,
dass sich 'irgendwas aufhängt' läßt keine qualifizierten Schlüsse zu

du hast noch nicht mal erwähnt, welchen Wert schlagzeit enthält
 
"Thread.sleep(schlagzeit)" reicht hier völlig aus, könnte aber auch durch "wait(schlagzeit)" ersetzt werden (ACHTUNG: Synchronisation nötig). "Thread.yield()" sorgt in der Regel auch für eine 100%ige Prozessorauslastung. Damit teilt der Thread dem System mit, das er in der nächsten Runde ausgelassen werden möchte. Was nach wie vor fehlt, ist der Zwang-Abbruch ("an = false") im Catch-Block bzw. innerhalb der "while"-Schleife.
 
okay, dann poste ich mal das, was hinter draw steckt. draw ist eine Klasse die von JPanel abgeleitet ist, ich zeichne quasi in dieses JPanel selber rein.
Hier ist das, was hinter der Methode ZahlZeichnen steckt:

Java:
public void ZahlZeichnen(int zahl){
		this.zahl=zahl;
		repaint(); //Aufruf der paintComponent() Methode
}
	
public void paintComponent(Graphics g) {
    super.paintComponent(g);
        
    switch(zahl){
      case 0: g.drawImage(blank, 21, 0, this);break;
      case 1: g.drawImage(one, 21, 0, this); break;
      case 2: g.drawImage(two, 21, 0, this); break;
      case 3: g.drawImage(three, 21, 0, this); break;
      case 4: g.drawImage(four, 21, 0, this); break;
      case 5: g.drawImage(five, 21, 0, this); break;
      case 6: g.drawImage(six, 21, 0, this); break;
      case 7: g.drawImage(seven, 21, 0, this); break;
      case 8: g.drawImage(eight, 21, 0, this); break;
      case 9: g.drawImage(nine, 21, 0, this); break;
    }  		 
}

edit: schlagzeit nimmt korrekte werte an! das habe ich mir schon ausgeben lassen. da braucht ihr euch keine sorgen zu machen. schlagzeit pendelt im bereich zwischen 0,1 und 3 sekunden.
 
Zuletzt bearbeitet:
@ brezn
wahrscheinlich mein Post zwischendurch noch nicht gesehen, dennoch zur Wiederholung:
es ist immer noch kein Problem ersichtlich, egal was ZahlZeichnen alles macht

Methoden klein schreiben!

-------

Bei Java nicht! Hatte ich mal ausprobiert und die JVm macht einfach garnichts.
wird denn der Code dahinter ausgeführt oder macht das Programm an sich ne Endlos-Pause? 😉

man muss evtl. bisschen tricksen, also von gar nix wieder auf 'nur Schleifenvariable prüfen/ ändern' zurückgehen,
sonst gibts gar nen Compiler-Fehler (Unreachable Code)

Java:
public class Test
{
    public static void main(String[] args)
    {
        int a = 3;
        System.out.println("a");
        while (a > 2) {}
        System.out.println("b");
    }
}

edit:
oder doch mit while(true):
Java:
public class Test
{
    public static void main(String[] args)
        throws Exception
    {
        System.out.println("a");
        try
        {
            while (true) {}
        }
        catch (Exception e) {}
        System.out.println("b");
    }
}
was passiert da bei dir wenn nicht 100% CPU (auf einen Kern)?
 
Zuletzt bearbeitet von einem Moderator:
@SlaterB: also das problem ist dir noch nicht ganz so klar, meinst du?
also es ist so, wenn ich auf Start klicke, dann soll das Metronom anfangen zu zählen. bei mir zählt halt noch nichts und das Programm hängt sich anscheinend auf, weil man nichts mehr anderes anklicken kann und das ganze nur noch mit dem Task Manager beenden kann.

Ich habe an=false nun mal mit eingebaut, ändert aber nicht wirklich was. false wird auch nur von außerhalb gesetzt, also wenn ich auf den Button stopp klicke. von daher kann ich das nicht wirklich in die schleife einbauen.
Java:
public void zaehlen(){
		while(an){
			if(aktZahl>otakt) aktZahl=1;
			draw.zahlZeichnen(aktZahl);
			aktZahl++;
			try{   
				Thread.yield(); 
            }
            catch (Exception ex) {
            	an=false;
            }

		}
	}
 
Jetzt wird mir so einiges Klar. Kann es sein, das die "zaehlen()"-Methode gar nicht in einem eigenen Thread läuft? Wenn dem so ist, kannst du natürlich lannge darauf warten, das sich irgendwo anders noch was tut. Der Start-Button muß also einen neuen Thread starten, sonst wartet die gesamte Anwendung darauf, das die "while"-Schleife beendet wird.
 
wahrscheinlich unbewußt hast du nun in deinen Nebensätzen neue Informationen preisgegeben,
besser so als gar nicht,

es klingt so, als hättest du eine graphische Oberfläche, die nicht mehr reagiert, das bringt uns natürlich weiter,
solange ein ActionListener oder ähnliches ausgeführt wird, ist die GUI generell blockiert,

wenn du sekunden- oder minutenlange Tasks startest, dann gehören diese in separate Threads,
damit die GUI weiterarbeiten und auf andere Ereignisse reagieren kann

siehe
http://www.java-forum.org/java-faq-beitraege/7395-progressbars-algorithmen-und-multithreading.html

etwas einfacher
Java ist auch eine Insel – 15.33 AWT, Swing und die Threads
 
aha, okay, verstehe ^^
ich muss zugeben, ich kenne mich mit threads kein bisschen aus! ich hab nur mal gelesen, dass man eben aufpassen muss und der CPU noch luft zum atmen geben muss und das halt mit Yield oder Sleep ginge. Das da dann noch jede menge mehr dahinter steckt, wusste ich nicht.
dann les ich mich erstmal in diese Thread thematik ein und schrei dann nochmal, wenn ich wieder probleme habe ^^

vielen dank erstmal 😛

edit: @ spacerat: die zaehlen Methode ist nicht in einem thread.
@SlaterB: ja, ich habe eine GUI. darum ja auch JPanel und "zeichen" die ganze zeit. der ActionListener ist eigentlich schon beendet, das hat damit nix mehr zu tun. denke ich jetzt mal. der actionlistener wird dann aktiviert, wenn ich auf Start klicke. dann ruft die GUI klasse die Metronom Klasse auf und darauf die starte()-methode, die wiederum ruft die zaehlen()-methode auf. also dürfte der actionlistener damit nix mehr zu tun haben, oder?
 
Zuletzt bearbeitet:
was passiert da bei dir wenn nicht 100% CPU (auf einen Kern)?

Hmm stimmt 90-96% CPU Auslastung... Ich glaub ich hatte damals einfach nur eine leere Schleife definiert aber auch das geht grad nicht. Hm was hatte ich damals anders gemacht? *denk*

Ich hatte mich damals nämlich auch total gewundert, dass es eben nicht passierte.
 
so, ich hab jetzt mal in meinem buch über threads nach gelesen, aber wirklich viel stand da nicht drin.
ich habe eine Klasse Metronom, wo sich alles abspielt, also wo die schlagzeit ausgerechnet wird, wo hochgezählt wird etc... blöderweise funktioniert das immer noch nicht. ich hab alles so gemacht, wie es im buch stand.

Java:
public class Metronom extends Thread {
	Integer tempo, otakt, utakt;
	Zeichnen draw;
	Double zeit;
	boolean an=false;
	long schlagzeit;
	int aktZahl=1;
	String z;
	
	public Metronom(Integer tempo, Integer otakt, Integer utakt, Zeichnen draw){
		this.tempo=tempo;
		this.otakt=otakt;
		this.utakt=utakt;
		this.draw=draw;
	}
	
	public void start(){
		switch(utakt){
    		case 1: zeit = 60.0/tempo*4*1000;break;
    		case 2: zeit = 60.0/tempo*2*1000;break;
    		case 4: zeit = 60.0/tempo*1000;break;
    		case 8: zeit = 60.0/tempo/2*1000;break;
		}
		schlagzeit=zeit.longValue();  //Umwandlung von Double in Long
		System.out.println(schlagzeit);  //Zum Test ausgeben
		an=true;
		run();
	}
	
	public void run(){
		while(an){
			if(aktZahl>otakt) aktZahl=1;
			draw.zahlZeichnen(aktZahl);
			aktZahl++;
			try{   
				sleep(schlagzeit); 
            }
            catch (Exception ex) {
            	an=false;
            }
		}
	}
}
 
die Methode start() am besten nicht überschreiben und schon gar nicht run() aufrufen,
das kann so ja nicht in dem Buch stehen

was du an Initialisierung brauchst kommt entweder in den Konstruktor oder an den Anfang der run()-Methode

-------

statt von Thread zu erben implementiere lieber Runnable, dann kannst du gar nicht start() überschreiben,

Runnabe r = mein eigenens Runnable...;
new Thread(r).start();
 
ach was, jetzt funktionierts... habs so gemacht, wie du gesagt hast, allerdings immer noch mit extends Thread und nicht mit runnable.

es lag also daran, dass ich run() selber aufgerufen habe... darf ich das nicht? warum ned?

vielen dank für die hilfe.
 
run() ist eine Methode, wie sie auch a() oder b() heißen könnte, der Name alleine bewirkt noch nichts,
auch das Thread-Objekt ist zu großen Teilen ein normales Objekt ohne Sonderstatus

es bedarf schon einer Menge Hintergrund-Magie, damit da ein separater Thread abläuft,
und da lautet das Konstrukt eben:
start() aufrufen,
-> intern wird irgendwas gestartet was letztlich zu einem neuen Thread führt,
-> der dann run() aufruft

zu einem bestimmten Grad ähnlich einem ActionListener,
da ruft man die actionPerformed()-Methode ja auch nicht selber auf
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben