Heiner KückerThread Preprocessor (Präprozessor) |
|
Home Java-Seite Bit Packed Array ASM Improved heterogene Map, HMap Constraint Code Generator JSP WorkFlow PageFlow FlowControl Page Flow Engine Web Flow Engine Control_and_Command JSP_Spreadsheet Code-Generator für Option-Either-Stil in Java verbesserter Comparator Fluent-Interface Code-Generator auf Basis einer Grammatik Visitor mit Multidispatch for-Schleife mit yield-return Kognitions-Maschine semantisches Netz Domain Parser Codegenerator_für hierarchische Datenstrukturen Expression_Engine Formula_Parser Thread Preprocessor State Transition Engine AspectJ Java_Explorer DBF_Library Kalender_Applet SetGetGen BeanSetGet CheckPackage LineNumbers GradDms Excel-Export StringTokenizer JspDoc JspCheck JSP-Schulung Java Server Pages Struts Ascii-Tabellen- Layouter Ascii-Baum- Layouter Ascii-Art-Fluss- Diagramm- Parser AsciiArt AssignmentMatrix Layouter StringSerial Silbentrennung JDBC_Schlüssel- Generierung bidirektional/ unidirektional gelinkte Liste Java_Sitemap Generator XmlBuilder RangeMap StringFormatter VersionSafe XCopy JTextField CommandLine- ParamReader Bitmap-Grafik MultiMarkable- Buffered- InputStream JavaCache JdomUtil CollectionUtil XML Really Pull Parser Log-Filter Remote-Protokoll Sudoku-Generator Delegation statt Mehrfachvererbung Disjunct Interval Set WebCam_Demo Weiterentwicklung_Java Alaska-XBase++-Seite Projekte Philosophien Techniken Konzepte Sudoku Kontakt / Impressum Links SiteMap Letzte Aktualisierung: 02.10.2007 |
Thread PräprozessorAuf dieser Seite präsentiere ich einen Preprozessor, der eine Methode einer Java-Klasse so instrumentiert, dass sie in kleine Teilstücke zerlegt wird, die von dem mitgelieferten Programm (Thread-Scheduler) koordiniert abgearbeitet werden.Dabei wechselt der Thread-Scheduler jeweils zwischen mehreren bei ihm angemeldeten Klassen, so dass die verschiedenen Methoden quasi-parallel abgearbeitet werden. Im Thread-Scheduler können unterschiedliche Strategien der Priorisierung implementiert werden. Durch die Umkehrung des Kontrollflusses des instrumentierten Codes, eignet sich der Preprozessor auch zur Aufbereitung von Source-Code als Ersatz zum Command-Pattern, zum Beispiel für Java-NIO oder für eventgesteuerte Applikationen, wie GUI- oder Web-Applikationen. Das Wiederaufnehmen des Programmflusses erlaubt ausserdem die Realisierung von Continuations, wie eingefrorene Programmzustände mit Aufruf-Stack, lokalen und globalen Variablen im Umfeld funktionaler Programmiersprachen genannt werden. Diese Art von Threads sind auch als Green-Threads beaknnt, was sie von nativen Threads, die auch auf einem bestimmenten Prozessor(bzw. Prozessor-Kern) residieren können. Siehe hierzu auch den Thread auf der News-Group de.comp.lang.java Konzept eigener Thread Präprozessor in Java ------------------------------------------- Ich nehme eine Java-Klasse und parse diese ein. 01: class MyThread { 02: 03: public void run() { 04: while ( isRun ) { 05: while ( nixZuTun ) { 06: //###yield 07: } 08: tueWas(); 09: } 10: } 11: 12: } (Der Meta-Befehl ###yield ist (noch) nicht fertig) Dazu benutze ich natürlich meinen DomainParser: Daraus wird Code generiert. Die run-Methode des eigenen Thread wird in einzelne Anweisungen zerlegt und diese werden in einem grossen switch-Verteiler untergebracht. switch (program_counter) { case 4: { boolean mythread_condition = ( isRun ); if ( ! mythread_condition ) program_counter = 9; } break; case 5: { boolean mythread_condition = ( nixZuTun ); if ( ! mythread_condition ) program_counter = 7; } break; case 6: { Scheduler.yield( this ); } break; case 7: { } break; case 8: { tueWas(); } break; case 9: { } break; case 10: { Scheduler.terminate( this ); } break; } Eine Besonderheit sind Schleifen und Verzweigungen. Diese werden als Jumps umkodiert. Ich gehe hier mal vereinfachend davon aus, dass die Grössenbegrenzung für Methoden und Klassen kein Problem darstellt. Ein Thread wird einfach als Klasse instanziiert und dem Scheduler zum Abarbeiten übergeben: MyThread_Generated myThread = new MyThread_Generated(); Scheduler.start( myThread ); Der Scheduler setzt den Thread an das Ende (oder Anfang optional) einer LinkedList und holt sich aus der Liste den nächsten abzuarbeitenden Thread. Im Thread gibt es eine reservierte Member int 'program_counter' mit dem als nächsten auszuführenden schwitch-Zweig. Abgearbeitet Threads werden an das Ende der Task-Liste gesetzt oder bei höherer Priorität weiter vorn eingefügt. Für den Source sollte es spezielle Direktiven geben, um Blöcke als Atom zusammenzufassen (noch nicht fertig): //###atom begin ... //###atom end Diese Blöcke werden in einem switch-Zweig zusammengefasst. Damit der Thread beendet werden kann, muss ein 'return' und das Beenden der run-Methode speziell instrumentiert werden. Beispiel Folge-Adresse -1 bedeutet, der Thread ist terminiert. Irgendwie muss die Maschine starten. Es muss also einen main- oder Ur-Thread geben. Zum Unterstützen von Unterprogrammen müsste ein Stack gebaut werden. Wenn die run-Methode andere Methoden aufruft, die nicht instrumentiert sind, könne diese nicht unterbrochen werden. Die run-Methode darf nur Member-Variable benutzen oder lokale Variable innerhalb eines atomaren Blockes. Sonst müsste am Anfang jedes switch-Zweiges die lokalen Variablen geladen und am Ende wieder gesichert werden. Der Scheduler ist ein guter Kandidat für einen Debugger. Mit einer GUI mit Code-, Variablen- und Thread-Fenster, Run, Einzelschritt usw. könnte man da was machen. Weiter wären zu implementieren sleep (unter Beachtung Performance-Problematik Sytem.currentTime, siehe Java- Spektrum), wait, join, Heben und Senken der Thread-Priorität dauerhaft oder temporär. Zur effektiven Fehlersuche müsste die Zeile (und eventuell auch Spalte) des Originalcodes zu den switch-Zweigen gemappt werden und auftretende Exceptions im Scheduler gefangen und mit Zusatzinformationen über die Originalcodestelle ausgestattet weitergeworfen werden. Wofür könnte man so ein Framework benutzen ausser zum Testen des Konzepts ? Ich sehe Anwendungsmöglichkeiten in der Fluss-Steuerung für Web-Apps und GUI-Apps, sowie der Zustands-Steuerung, für die sonst ein Zustandsautomat benutzt wird. Ich glaube, dass man so ein Framework gut wiederverwenden kann. Test-Implementierung (Prototype) -------------------------------- Packages de.cnc.** Domainparser und SharedUtils Package thread.codegenerator Klasse ThreadCodeGenerator Der Code-Analyser und Code-Generator Nach dem Generieren in Eclipse Refresh auf Projekt (F5) Package thread.generatedsrc Klasse Generated_TestThread generierter Code vom Scheduler ausführbar Package thread.scheduler Klasse ThreadScheduler Thread-Scheduler (arbeitet im Moment nur mit Round Robin Algorithmus) Interface ThreadInterface Interface für generierten Code, wird vom ThreadCodeGenerator eingefügt, nicht im Source verwenden Klasse TestMain Testklasse Main Package thread.source Klasse TestThread zu analysierende und in instrumentierten Code umzuwandelnde Klasse wird nicht selbst gestartet, muss aber gültig und compilierbar und lauffähig sein Zur Zeit wird nur while sowie if - else if - else unterstützt. Damit kann bei Bedarf for, do while und switch nachgebaut werden. Atomare Blöcke sind noch nicht fertig. Dafür jeweils eine extra Methode schreiben, die sind atomar. Unterprogramme werden noch nicht instrumentiert. Join ist möglich. Dazu Idee: Nicht nur mit Ende des Threads joinen, sondern mit einem definierten Punkt im Thread, entweder über bennanten Join-Point (String in Map oder so) oder Join-Object ( Umschaltung Status nicht gejoined (default) zu joined). Siehe hierzu auch DomainParser
Download der Quelldateien THREAD_PREPROCESSOR.zip
Achtung: Erweiterungen und Fixes stelle ich ohne Historie
und ohne Ankündigung hier bereit. Lizenzbedingungen:
Die Programme, Quelltexte und Dokumentationen können ohne
irgendwelche Bedingungen kostenlos verwendet werden. |