C# - Schleife funktioniert nicht ?
Dieter72
- programmiertechnik
0 unknown0 Encoder0 dedlfix0 Frank (no reg)
Hallo,
ich bin gerade dabei mich ein wenig in C# auszutoben und stehe derzeit vor einem, für mich komischen, Problem.
Mit meinem nachfolgenden Code will ich den Thread 0-19 falls:
a) die INT restTLD > 0
und
b) einer der 20 Threats nicht läuft selbigen starten.
Die INT genauso wie die Counter-Variable sind mit korrekten Werten versehen (in dem Threat gibt es entsprechende Ausgaben).
Mein Problem an der ganzen Geschichte ist, das die Schleife genau nur einmal durchlaufen wird, obwohl dann z.B. in der INT restTLD noch ein Wert von z.b: 19 ist und alle Threats auf STOPPED stehen.
Das einzige wie ich mir das ganze Erklären kann, das es zu einer Exception kommt und dann dadurch die Schleife verlassen wird.
Im Debugger wirft das Teil übrigens nach dem ersten Durchlauf (ohne Fehler) eine Threat.Start-Exception - was aber n.m.E. doch eigentlich nicht dafür sorgen kann, das die WHILE abgebrochen wird, oder?
In den Threats wird übrigens eine Methode aufgerufen, die ebenfalls try/catch beinhaltet; dieses ist nicht umgänglich, da in dieser Methode Webrequests ausgeführt werden und es hierbei (leider) immer zu einer Exception kommen kann.
Daher hoffe ich, wie immer ;-), auf eure Hilfe...
while (Program.restTLD > 0)
{
if (Program.restTLD > 0 && t0.ThreadState != ThreadState.Running) { ++Program.counter; try{t0.Start(ezWURLS[Program.counter - 1]);} catch(Exception){} }
if (Program.restTLD > 0 && t1.ThreadState != ThreadState.Running) { ++Program.counter; try{t1.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t2.ThreadState != ThreadState.Running) { ++Program.counter; try{t2.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t3.ThreadState != ThreadState.Running) { ++Program.counter; try{t3.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t4.ThreadState != ThreadState.Running) { ++Program.counter; try{t4.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t5.ThreadState != ThreadState.Running) { ++Program.counter; try{t5.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t6.ThreadState != ThreadState.Running) { ++Program.counter; try{t6.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t7.ThreadState != ThreadState.Running) { ++Program.counter; try{t7.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t8.ThreadState != ThreadState.Running) { ++Program.counter; try{t8.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t9.ThreadState != ThreadState.Running) { ++Program.counter; try{t9.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t10.ThreadState != ThreadState.Running) { ++Program.counter; try{t10.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t11.ThreadState != ThreadState.Running) { ++Program.counter; try{t11.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t12.ThreadState != ThreadState.Running) { ++Program.counter; try{t12.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t13.ThreadState != ThreadState.Running) { ++Program.counter; try{t13.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t14.ThreadState != ThreadState.Running) { ++Program.counter; try{t14.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t15.ThreadState != ThreadState.Running) { ++Program.counter; try{t15.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t16.ThreadState != ThreadState.Running) { ++Program.counter; try{t16.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t17.ThreadState != ThreadState.Running) { ++Program.counter; try{t17.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t18.ThreadState != ThreadState.Running) { ++Program.counter; try{t18.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
if (Program.restTLD > 0 && t19.ThreadState != ThreadState.Running) { ++Program.counter; try{t19.Start(ezWURLS[Program.counter-1]);} catch(Exception){} }
}
VG
Dieter
Das einzige wie ich mir das ganze Erklären kann, das es zu einer Exception kommt und dann dadurch die Schleife verlassen wird.
Die fängst du ja, also läuft die Schleife weiter.
Im Debugger wirft das Teil übrigens nach dem ersten Durchlauf (ohne Fehler) eine Threat.Start-Exception -
Eine, oder jedesmal eine?
was aber n.m.E. doch eigentlich nicht dafür sorgen kann, das die WHILE abgebrochen wird, oder?
Abgebrochen nicht, aber nach dem 1. Durchlauf der Schleife wird der Thread ja wieder gestartet. Geht es dann auf einmal? warum?
In deiner Schleife steht x-mal fast der selbe Code. Die Namen t0 bis tn legen schon nahe hier ein Array zu nutzen.
Om nah hoo pez nyeetz, unknown!
In deiner Schleife steht x-mal fast der selbe Code. Die Namen t0 bis tn legen schon nahe hier ein Array zu nutzen.
und if (Program.restTLD > 0 && ... )
ist ebenfalls nicht notwendig, denn das fragst du ja bereits in der while-Schleife ab.
Matthias
Hallo nochmal,
das Problem ist, das die Schleife genau einmal abgearbeitet wird, es erfolgt KEIN zweiter Durchlauf. Nach dem Durchlauf, d.h. Threat 0-19 kommt es zu einer Threat.Start.Exception.
Mein Versuch den Fehler zu lokalisieren ist leider kläglich gescheitert.
Wenn ich nach dem (einzigen) Durchlauf der Schleife [also nach dem letztem Threat.Start, in dem Fall der t19] den Status z.B. vom t0 ausgebe erhalte ich Stopped.
Nach meiner Logik sollte also die Schleife (da ja der Wert > 0 ist) weiter durchlaufen, was aber nicht erfolgt.
Z.Zt. starte ich das ganze mit dem Zählwert 57, es erfolgt der Threatstart 0-19 und nachdem alle Threats abgearbeitet worden sind, bin ich bei einem Zähler von 37 (der Zähler wird im übrigen am Ende der Methode die durch den jw. Threat aufgerufen wird, heruntergezählt.
Auch kann ich es mir nicht erkären das wenn ich z.B. in dem ersten Durchlauf t0 - t19 gestartet habe und dann z.b. t3 fertig ist, dieser (in dem Beispiel t3) nicht wieder mit einem neuen Wert gestartet wird.
Das Teil startet alle Threats, arbeitet diese (übrigens korrekt) ab und wirft dann besagte Exception und nichts geht mehr (kein Absturz, sieht eher so aus als würde er die While ohne Beachtung der IFs unendlich durchlaufen).
Bzgl. Thrat-Bezeichner als Array und die doppelte if bzgl Rest:
Ja, müsste ich noch ändern, aber erstmal muß das Teil so laufen ;-) / oder ich verstehen, was ich falsch gemacht habe...
Gruss
Dieter
Mein Versuch den Fehler zu lokalisieren ist leider kläglich gescheitert.
Wenn du nicht n-fach alles in eine Zeile schreiben würdest, sondern 1 mal auf mehrere Zeilen aufteilen würdest, könnte man das debuggen.
Wenn ich nach dem (einzigen) Durchlauf der Schleife [also nach dem letztem Threat.Start, in dem Fall der t19] den Status z.B. vom t0 ausgebe erhalte ich Stopped.
Also läuft irgendwas schief!
Nach meiner Logik sollte also die Schleife (da ja der Wert > 0 ist) weiter durchlaufen, was aber nicht erfolgt.
Sicher?
Z.Zt. starte ich das ganze mit dem Zählwert 57, es erfolgt der Threatstart 0-19 und nachdem alle Threats abgearbeitet worden sind, bin ich bei einem Zähler von 37
Dann sollte die Schleife ein 2. mal durchlaufen werden. Da hilft ein Breakpunkt.
(der Zähler wird im übrigen am Ende der Methode die durch den jw. Threat aufgerufen wird, heruntergezählt.
Das ist aber nicht threadsafe. In c++ gäbe es da wenigstens die Interlocked... Methoden.
Wann der Thread am Ende angekommen ist kannst du außerdem nicht wissen, da kann deine Schleife schon ein paar mal umsonst gekreiselt haben.
Das Teil startet alle Threats, arbeitet diese (übrigens korrekt) ab und wirft dann besagte Exception und nichts geht mehr (kein Absturz, sieht eher so aus als würde er die While ohne Beachtung der IFs unendlich durchlaufen).
Das ist was anderes als du oben beschrieben hast. Wie ist denn t3.ThreadStat?
oder ich verstehen, was ich falsch gemacht habe...
Ich kenne C# nicht, aber auf jeden Fall würde ich die Synchronisation nicht über einen Counter machen. Du brauchst eine Semaphore, mit der du den Mainthread schlafen legst, bis ein Thread NACH (das ist unter Umständen nicht so einfach) Beendigung das Event zum Aufwachen schickt
Im Debugger wirft das Teil übrigens nach dem ersten Durchlauf (ohne Fehler) eine
Wie wird die geworfen? Kann sein dass du hier Exceptions angezeigt bekommst die zwar geworfen werden, die aber danach trotzdem in einem catch landen. Das ist dann nur eine Info vom Debugger an dich. Kann man abstellen.
Ein leeres catch ist übrigens meistens Unsinn, hier fängst du eine Exception und lässt sie ins leere laufen. Vielleicht wäre da schon die Lösung deines Problems zu finden.
Das einzige was hier auftreten könnte wäre dass Program.counter einen ungültigen Wert enthält. Den solltest du vorher prüfen, nicht einfach aufs Array zugreifen und schauen ob es knallt. Das ist unsauber.
Diese Zeilen schreien übrigens nach der Auslagerung in eine separate Methode.
- was aber n.m.E. doch eigentlich nicht dafür sorgen kann, das die WHILE abgebrochen wird, oder?
In deinem Fall nicht, denn du fängst die Exception. Demnach sollte das wirklich weiterlaufen.
Tach!
Mit meinem nachfolgenden Code will ich den Thread 0-19 falls:
Was machst du, wenn du morgen eine gößere Anzahl an Threads haben möchtest? Den Code kopieren und alle Zahlen anpassen? Was machst du, wenn du einen Fehler feststellst oder etwas ändern musst? Durch sämtliche Codekopien durchlaufen und den entsprechenden Teil ändern? Du weißt, dass es Arrays oder List<> gibt? Wann immer du denkst etwas mehrfaches mit durchnummerierten Variablen zu benötigen, ist Array/List<>/etc. das eigentliche Mittel der Wahl.
b) einer der 20 Threats nicht läuft selbigen starten.
Wenn ein Thread (mit d am Ende) einmal gestoppt ist, kann er nicht wieder gestartet werden. Wenn du ein Problem mit einer Methode oder ähnlichem hast, solltest du zuerst einmal die Dokumentation aufsuchen und die dortigen Anmerkungen lesen.
Die INT genauso wie die Counter-Variable sind mit korrekten Werten versehen (in dem Threat gibt es entsprechende Ausgaben).
Mein Problem an der ganzen Geschichte ist, das die Schleife genau nur einmal durchlaufen wird, obwohl dann z.B. in der INT restTLD noch ein Wert von z.b: 19 ist und alle Threats auf STOPPED stehen.
Wenn die (Kontroll-)Ausgaben lediglich in den Threads stehen, können sie auch bei weiteren Durchläufen nicht ausgegeben werden, weil die Threads ja nicht erneut gestartet werden können.
Im Debugger wirft das Teil übrigens nach dem ersten Durchlauf (ohne Fehler) eine Threat.Start-Exception - was aber n.m.E. doch eigentlich nicht dafür sorgen kann, das die WHILE abgebrochen wird, oder?
Wenn eine Exception nicht gefangen wird, stirbt das gesamte Programm an der Stelle. Man kann auch in den catch-Block eine Kontrollausgabe (oder einen Breakpoint) setzen.
Und sicherlich möchtest du dich über das Thema ThreadPool informieren.
dedlfix.
Hallo Dieter72,
einfach so kreuz und quer ueber verschiedene Threads Variablen inkrementieren muss schief gehen. Verwende Interlocked.Increment(ref int/long).
Dekrementieren koennte auch nicht schaden, und ueberhaupt Thread Synchronisation.
Allein vom Blick auf den Code wuerde ich meinen, du faehrst deutlich besser mit einem Async Producer/Consumer Pattern. Stichworte zum Googeln: Task<>, TPL, ConcurrentQueue<> bzw. Blocking Collections, TPL Dataflow: Du definierst eine Queue oder Collection (welche fuer multithreaded Zugriff geeignet ist!) und startest fuer jedes neu hinzugefuegte Element eine Hintergrundaufgabe: Lade URL Daten und untersuche nach neuen URLs dann packe diese wieder in die Queue und fertig. Web Spider Programme sind quasi eine Paradeanwendung fuer .Net TPL, da findest du genug Codebeispiele im Netz, die du klauen kannst. ;-)
Cheers,
Frank