K
Hi nochmals
Also, die Schleife in switchState() sollte eigentlich nie im Sinne eines Busy Wait laufen, sondern beenden, sobald der aktuell aktive Zustand durch state referenziert wird.
Ein Beispiel: doSomethingA() wird ausgeführt, was eigentlich nur einen Wechsel von StateA zu BusyA verursacht. Bevor jemand wieder (z.B. via getState()) auf Device zugreift, beendet BusyA seine Funktion, erstellt einen neuen StateA und verweist mit getNextState() darauf.
Wenn nun jemand z.B. getState() ausführt, um den aktuellen Status des Gerätes zu erhalten, muss dieser erst via switchState() ermittelt werden. Momentan zeigt Device::state nämlich noch auf das ursprüngliche StateA Objekt. Dessen getNextState() zeigt aber auf ein BusyA-Objekt, also zieht die Schleife, state wird auf das BusyA-Objekt umgeleitet und das StateA-Objekt gelöscht. Das neue BusyA-Objekt zeigt allerdings erneut auf ein anderes Objekt, die Schleife wird erneut durchlaufen, das BusyA-Objekt gelöscht und Device::state zeigt auf das zweite StateA-Objekt.
Dieses 2. StateA-Objekt zeigt nun allerdings mit getNextState() auf sich selbst (das soll so sein, solange ein Status aktiv ist), weshalb die Schleife abbricht und der Status zurückgegeben werden kann. Da auch alle anderen Device-Operationen getState() verwenden, anstatt direkt auf state zuzugreifen, bist du immer sicher, den aktuell aktiven Status zu haben (wobei du dich höchstens noch gegen Multithreading-Anomalien absichern musst). Eine Schleife ist es nur deshalb, weil mehrere State-Wechsel vorkommen könnten, ehe erneut ein switchState() aufgerufen wird.
Im Beispiel würde das also heissen, dass doSomethingA() sofort returnieren würde, nachdem es lediglich einen neues BusyA()-Objekt erstellt hat und via getNextState() darauf verweist. Wird switchState() direkt am Ende von doSomethingA() aufgerufen, würde das BusyA-Objekt auch gleich als Device::state registriert - obwohl das nicht zwingend nötig ist, da das ja eh beim nächsten getState() erledigt wird. Damit wird eigentlich nur verhindert, dass nicht unnötig Objekte auf dem Heap rumschwirren, die eigentlich gar nicht mehr gebraucht werden - was allerdings eh passieren kann und weshalb ich mich persönlich mit einem switchState() in getState() begnügen würde.
Zu deinen anderen Fragen: Ja, die Ausführung der eigentlichen Arbeit würde dann im BusyA Objekt gestartet, welches z.B. gleich im Konstruktor die dazu nötigen Threads erstellt. Finde ich auch irgendwie logisch - das Ding heisst nicht umsonst Busy . Das zu koordinieren stellt dich allerdings wieder vor die üblichen PnProg-Probleme: Was, wenn ein TimeOut genau zur gleichen Zeit wie ein Resultat vorliegt? Im Timeout-Fall müsstest du den Rechenthread darüber informieren, dass er beenden soll (z.B. über ein simples Flag) und umgekehrt. Und du müsstest irgendwo die beiden Threads dann auch wieder POSIX-mässig joinen (da böte sich erneut die getNextState()-Methode oder der Destruktor an), damit keine verwaisten Threads herumstreunen .
Die ganze Arbeit in den BusyA zu verlegen hätte dann, wie bereits erwähnt, zur Folge, dass doSomethingA sofort returnieren würde und einen Statuswechsel provozierte. Von da aus kannst du dann ja beliebig Exceptions werfen, sollte nochmal jemand auf doSomethingX zugreifen - das hängt von deiner Implementation von BusyA ab. Und BusyA könnte selbstverständlich auch zusätzlich noch Callback-Funktionen aufrufen, ganz wie es dir beliebt. Falls das deinem Programmfluss hilft und lästiges Polling auf Device::getState() vermeidet - warum nicht.
greeetz