Multithreading & Laden von Dateien
-
Hi.
Ich hab eine Klasse die meine Resourcen lädt. Dateien, Bilder etc.
Jetzt hab ich ein kleines Verständnis-Problem:
Wenn ich das in einem extra Thread mache (das laden), wie verfahre ich im Hauptthread?
Kurzer Pseudo-Code:int main() { Icon* _icon = Resource->Load("Icon_1.ico"); _icon->Display(); _icon->MoveAround(); etc(); }So, während ich noch in einem anderen Thread das Objekt lade, wird im Hauptprozess dieses bereits verwendet.
Jetzt gibts da mehrere Möglichkeiten:
* Ich erzeuge einen Mutex und warte bis der wieder frei ist.
--> Wäre Blödsinn, dann kann ichs gleich im hauptthread machen. Oder welchen Vorteil soll das dann bringen, wenn der Hauptprozess trotzdem blockiert ist (WaitForSingleObject, WinApi)?
* Ich erzeuge ein "Dummy-Icon" (weiss), das wird befüllt, sobald das richtige geladen wurde ("Zeiger umbiegen").
--> Undefinierbares Verhalten?
* Ich erzeuge eine Critical-Section und wenn diese wieder frei ist, wird das Objekt verwendet.
--> Gibt es unter Linux bzw in den Posix-Threads so etwas wie Critical-Sections? Ich denke da an eine Portierung in Zukunft.Wäre nett, wenn mir da jemand unter die Arme greifen könnte, denn Multithreading ist für mich ein nicht einfaches Thema und gerade der OpenMP-Artikel hat mir Lust auf mehr MT gemacht, hihi.
rya.
-
Ressourcen zu laden ist meines Erachtens sowieso etwas, was blockieren sollte. Was du noch machen könntest wäre, statt eines echten Zeigers einen Smartpointer zu verwenden, dessen Dereferenzierung blockt, wenn das Laden noch nicht abgeschlossen ist (oder vielleicht sogar dann erst lädt).
Auf diese Weise könntest du beim Programmstart alle vielleicht jemals benötigten Ressourcen laden, per Policy kann dann geregelt sein, ob sie direkt geladen werden (also in die Ladewarteschlange gehangen werden) oder erst dann, wenn sie tatsächlich benutzt werden.
Multithreading käme dann so rein, dass im Hintergrund ständig der Ladethread läuft, der alles, was du so in seine Warteschlange reintust ausführt.
-
Wenn du das File (Icon, ...) sofort verwenden willst/musst nachdem du den "Lade-Aufruf" lostreten kannst, dann ist die Verwendung eines Lade-Threads schlicht und ergreifend Blödsinn.
Wenn du dagegen einen Fall hast wo du schon eine Zeit lang vorher weisst welches File du bald mal brauchen wirst sieht die Sache anders aus. In dem Fall könnte man die von .filmor erwähnten speziellen "smart pointer" verwenden die man üblicherweise auch einfach "futures" nennt.
Anwendung sähe dann ca. so aus:
int main() { future<Icon*> f = Resource->Load("Icon_1.ico"); tu_was_dazwischen(); Icon* i = f.get(); // hier wird gewartet i->Display(); i->MoveAround(); etc(); }
-
Danke für die Antworten, das Beispiel von hustbaer ist so was ich meine und Ihr habt ja meine Überlegungen zum teil bestätigt (:. Lag ich also doch nicht so falsch hehe.
Das mit den Futures... kennt Ihr da eine nette Implementation für sowas, optimalerweise nicht boost (ausser es braucht nur Header und keine Libs von boost)?
Ansonsten muss ich sowas halt selber basteln, sollte nicht allzu schwer sein.
rya.
-
Ehrlich gesagt kenne ich tatsächlich nur eine Boost-Implementierung. Was hast du dagegen?
-
Mmmh, schwieriges Thema.
Mir ist Boost zu umständlich und die Header produzieren eine Menge Warnungen, zumindest unter VC++ auf W4.
Hauptgrund ist aber auch, dass es zuviele DLL am Ende werden, wenn man dynamisch linkt. Und da ich momentan eine Dynamische Library schreibe, werden mir das auch zuviele Abhängigkeiten. Und Boost ist eine dicke Abhängigkeit mMn.
Ich weiss auch nicht, mir is die Lib einfach zu fett und ich bin vllt zu blöd die Features richtig zu nutzen. Also ich such hier den Fehler echt bei mir, Boost is ne feine Sache, aber ich komm nicht so richtig klar damit, obwohl ich grundsätzlich mit fremden Libs eingentlich immer recht gut klarkomme.
Das gleiche als bsp. bei mir mit CEGUI.. isn feines Ding, aber ich packs nicht. Zuviele Exceptions, zu umständlich designed in meinen Augen, keine richtige Doku im Paket etc. Aber ich bin wxWidgets-User, ich bin verwöhnt was Dokumentation angeht.
Mit manchen Sachen werd ich halt nicht warm :D.
rya.
-
.filmor schrieb:
Ehrlich gesagt kenne ich tatsächlich nur eine Boost-Implementierung. Was hast du dagegen?
Futures in der Boost? Wo? (hast du Link?)
In der 1.36 hab ich nix diesbezüglich gefunden...Sandbox/Vault hab ich nicht geguckt, die Sachen die da drin sind sind mir etwas zu "volatile".
@Scorcher24:
Ich kenne leider keine fertige Implementierung. Das "sollte nicht allzuschwer sein" ... hm. Naja, viel Spass damit
Wenn du natürlich keine uralt-Compiler unterstützen musst, und NUR Thread-Futures implementieren willst, dann sollte das in absehbarer Zeit gehen.
-
http://braddock.com/~braddock/future/
Das Ding meinte ich. Hab aber die Mailing-Liste ne Weile nicht mehr verfolgt, kA wie weit der damit gekommen ist, ist aber auf jeden Fall schon im Review Queue.
-
Ich kenne leider keine fertige Implementierung. Das "sollte nicht allzuschwer sein" ... hm. Naja, viel Spass damit
Wenn du natürlich keine uralt-Compiler unterstützen musst, und NUR Thread-Futures implementieren willst, dann sollte das in absehbarer Zeit gehen.naja, meine Resourcen-Klasse arbeitet ja schon fast so. Die Resourcen werden per Script in eine Liste geworfen und wenn das script fertig ist, werden Sie entweder sofort geladen (m_precache = true) oder später (m_precache = false). Das einzigste was ich jetzt noch einbauen muss, ist eben dass das Precaching in einem anderen Thread stattfindet. Und ja, momentan erst mal nur Thread-Futures, denn die brauche ich.
Aber hast du einen Link zu einer guten Lektüre über Futures und deren Arten? Interessiert mich jetzt doch mal genauer. Dachte ich kann mir was drunter vorstellen, aber jetzt möcht ich es genau wissen (:.
rya.
-
Nö hab keinen Link parat. Vielleicht sollte ich mal anfangen gute Artikel die ich gelesen habe zu katalogisieren

Ist aber relativ einfach.
Eine "future" ist ja bloss ein Teil was irgendwann später mal das Ergebnis von irgendeiner Funktion beinhalten wird.
So eine Funktion kann schonmal viel sein: ein beliebiger Funktor, irgendwelche IO Operationen, ...
Dann ist auch nicht gesagt wo diese Funktion ausgeführt wird. Bei IO könnte die Future intern z.B. asynchrones IO statt eines Threads verwenden. Oder die Future könnte genauso die Funktion sofort ausführen, also eine "fake-future". Oder eine "non-threaded-lazy-future", die die Funktion erst ausführt wenn der Wert das erste mal abgefragt wird. Oder man könnte anstelle eines Threads einen Thread-Pool verwenden, wodurch man nicht a) zuviele Threads gleichzeitig laufen hat wenn viele Futures ausstehen und b) den Overhead vermeidet für jede Future einen eigenen Thread anlegen zu müssen.
Nochmal zurück zu asynchronem IO: sehr ähnlich sind Dinge wo man sich selbst schon irgendwas gebastelt hat was asynchron Daten liest/schreibt, z.B. das Aufnehmen/Abspielen von Audiodaten über die Soundkarte. Hier könnte die Klasse die das implementiert das Ergebnis genauso als Future anbieten, falls es in der jeweiligen Anwendung Sinn macht.