Übergabe mehrerer Argumente an einen SDL_Thread

Algorithmen, Sprachunabhängige Diskussionen zu Konzepten, Programmiersprachen-Design
Antworten
Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Übergabe mehrerer Argumente an einen SDL_Thread

Beitrag von Dirty Oerti » Di Apr 14, 2009 11:09 am

Tag :)

Code: Alles auswählen

 SDL_Thread *SDL_CreateThread (int (*thread_func)(void*), void *thread_parameter);
Mein Problem ist, dass ich Funktionen von folgendem Typ als Thread starten will:

Code: Alles auswählen

int thread_func(GameManager*,void*)
Bei "GameManager" handelt es sich um eine Klasse. Der Thread soll durch eine Methode dieser Klasse gestartet werden.

Ein Beispiel:

Code: Alles auswählen


struct parameter {
     char eins[3];
     char zwei[3];
};


int stupid (GameManager* the_app, void* parm) {
   struct parameter *parm_str = (struct parameter*) parm;
   std::cout << parm_str->eins << parm_str->zwei << the_app->getName();
   return 0;
}



// ...

GameManager app;

struct parameter *parm = new struct parameter;
parm->eins = "ab";
parm->zwei = "ba";


app.addThread(stupid,parm);

// ...
Die Funktion stupid soll nun also als Thread gestartet werden. Sie soll als Argument einen Zeiger auf die "startende Klasse" (app) zusätzlich zu einem "normalen" void-Argument bekommen.

In der Methode addThread soll der SDL_Thread erstellt werden.

Jetzt hab ich mir gedacht, ich bastle mir ein Übergabestrukt wei z.B.

Code: Alles auswählen

typedef struct {
	GameManager *app;
	void *parm;
	int (*thread_func)(GameManager*,void*);
} ThreadParm;
Das lasse ich nun von addThread ausfüllen und übergebe es an einen SDL_Thread, der eine Funktion "thread_starter" aufruft.

thread_starter liest das Strukt aus und startet die eigentliche Threadfunktion, dafür aber mit den richtigen Parametern.

Nun mein Problem:

Code: Alles auswählen

// in addThread
	ThreadParm *parm = new ThreadParm;
	parm->app = this;
	parm->parm = thread_parm;
	parm->thread_func = thread_func;

	unsigned int ret = SDL_CreateThread(thread_starter,parm);
Hier habe ich das Strukt ausfüllen lassen. Das Strukt wurde hier aber per new allokiert. Heißt, ich muss es auch wieder löschen.
Der thread_starter sieht so aus:

Code: Alles auswählen

int thread_starter (void *parmstr) {
	ThreadParm *parm = (ThreadParm*) parmstr;
	parm->thread_func(parm->app,parm->parm);
	delete parm;
	return 0;
}
Alles schön und gut, wenn ich nun aber den Thread kille, während er noch in der eigentlichen Threadfunktion ist, dann wird das Strukt für die Übergabe nie gelöscht.
Wie bekomm ich das hin, das ich keine Speicherlecks hab?

Ich hatte mir schon gedacht, dass ich evtl einen zweiten Thread starte, der darauf wartet, das der erste beendet wird und dann das Übergabestrukt löscht, aber wäre das nicht etwas zu viel an Threads?


Ich könnte natürlich auch das hier versuchen:

Code: Alles auswählen

// in addThread
	ThreadParm parm;
	parm.app = this;
	parm.parm = thread_parm;
	parm.thread_func = thread_func;

	unsigned int ret = SDL_CreateThread(thread_starter,&parm);
Aber hier wird parm doch auf dem Stack erstellt, heißt sobald die Methode addThread fertig ist und per Return zurückgibt wird das parm wieder gelöscht.
Oder?


:)
Hilfe?


@fat-lobyte: Geht das vielleicht besser mit boost?
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Übergabe mehrerer Argumente an einen SDL_Thread

Beitrag von Dirty Oerti » Di Apr 14, 2009 12:28 pm

Kann es sein, dass eine Begrenzung zwecks der Anzahl an Threads gibt, die SDL erstellen kann?
Ich bekomme nicht mehr als ca 190 Threads her.
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Kerli
Beiträge: 1456
Registriert: So Jul 06, 2008 10:17 am
Wohnort: Österreich
Kontaktdaten:

Re: Übergabe mehrerer Argumente an einen SDL_Thread

Beitrag von Kerli » Di Apr 14, 2009 12:42 pm

Dirty Oerti hat geschrieben:Kann es sein, dass eine Begrenzung zwecks der Anzahl an Threads gibt, die SDL erstellen kann?
Davon habe ich eigentlich noch nie gehört. Aber durch die Hardware wird es wahrscheinlich schon eine Beschränkung geben. Es bekommt zb jeder Thread einen gewissen Platz im Arbeitsspeicher für seinen Stack.
Dirty Oerti hat geschrieben:Ich bekomme nicht mehr als ca 190 Threads her.
Was machst du denn eigentlich mit so vielen Threads? Nach Möglichkeit solltest du die Threadanzahl vl doch etwas niedriger halten, ansonsten wirst du ws auch einmal Performanceprobleme haben.
"Make it idiot-proof and someone will invent an even better idiot." (programmers wisdom)

OpenGL Tutorials und vieles mehr rund ums Programmieren: http://www.tomprogs.at

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Übergabe mehrerer Argumente an einen SDL_Thread

Beitrag von fat-lobyte » Di Apr 14, 2009 3:42 pm

Dirty Oerti hat geschrieben:Tag :)
Tag zurück.

Also erstens: so ganz hab ich nicht verstanden was du machen willst... Ich versuch trotzdem hilfreich zu sein.
Dirty Oerti hat geschrieben:Alles schön und gut, wenn ich nun aber den Thread kille, während er noch in der eigentlichen Threadfunktion ist, dann wird das Strukt für die Übergabe nie gelöscht.
Wie bekomm ich das hin, das ich keine Speicherlecks hab?
Richtig. Darf ich fragen was du mit "thread killen" meinst? Heißt das du schickst ihm einen Interrupt? Einen thread einfach zu "töten" ist eine sehr schlechte idee. Du solltest in dem thread "exit points" einrichten, mit denen du den thread notfalls unterbrechen kannst.
Dirty Oerti hat geschrieben:Ich hatte mir schon gedacht, dass ich evtl einen zweiten Thread starte, der darauf wartet, das der erste beendet wird und dann das Übergabestrukt löscht, aber wäre das nicht etwas zu viel an Threads?
Ja. Und außerdem viel zu kompliziert und fehleranfällig.
Dirty Oerti hat geschrieben: Aber hier wird parm doch auf dem Stack erstellt, heißt sobald die Methode addThread fertig ist und per Return zurückgibt wird das parm wieder gelöscht.
Oder?
Ja, so ginge es auch.

Dirty Oerti hat geschrieben:@fat-lobyte: Geht das vielleicht besser mit boost?
Auf jeden Fall. Als allererstes gibts einmal die shared_ptr (die sind auch bei jedem neueren Compiler unter std::tr1:: zu finden).
shared_ptr halten einen Zeiger auf ein mit new allokiertes Objekt. Wenn alle shared_ptr, die auf dieses Objekt zeigen zerstört ist, wird auch das Objekt freigegeben.
Tatsache ist, das Freigeben spielt sich im Konstruktor ab. Wenn der nicht aufgerufen wird hast du erst wieder ein speicherleck. Deswegen nochmal die Frage: was genau meinst du mit "thread killen" ?

Zweitens:
Nutze doch boost threads!!
Die sind viel viel sauberer und klarer.

Code: Alles auswählen

#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>


struct Parameter 
{
     char eins[3];
     char zwei[3];
};



int thread_func(GameManager&, boost::shared_ptr<Parameter>)
{

    
}



// in wo auch immer du den thread starten willst:
    GameManager app( /* super toll initialisieren */);
    boost::shared_ptr<Parameter> parm(new Parameter);
    parm->eins = "asd";
    parm->zwei = "fgh";

    boost::thread(
        boost::bind(
            &thread_func,
            boost::ref(app),
            parm
        )
    );
    
   
   
// nochmal mit erklärung
    // starte einen thread mit funktionsobjekt (oder funktion) x, 
    // das keine parameter bekommt
    boost::thread( x ); 
    
    // "Binde" die parameter an die thread_func funktion. Der Rückgabewert
    // ist ein Funktionsobjekt, das keine Parameter übernimmt
    boost::bind(&thread_func, ...); 

    // benötigt um referenzen durch boost::bind zu schleusen.
    boost::ref(app); 
Dirty Oerti hat geschrieben:Kann es sein, dass eine Begrenzung zwecks der Anzahl an Threads gibt, die SDL erstellen kann?
Ich bekomme nicht mehr als ca 190 Threads her.
190 Threads ?!? Was zur hölle hast du vor? Ne Armee von Zombifunktionen zu schreiben und damit ne Bank zu überfallen?

Ich sags ungern, aber die Performance wird unter aller Sau sein. Schau:
Die CPU kann pro core genau einen Thread behandeln. Deswegen laufen Threads nur scheinbar gleichzeitig ab. Wenn die CPU von einem auf einen anderen Thread schaltet muss das Betriebssystem und die CPU nicht wenig Arbeit verrichten. Wenn du 190 Threads hast, glaubst du die CPU kommt noch zu was anderem als Threads umzuschalten?
Haters gonna hate, potatoes gonna potate.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3123
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Übergabe mehrerer Argumente an einen SDL_Thread

Beitrag von cloidnerux » Di Apr 14, 2009 3:54 pm

Wie es aussieht, willst du einfach nur wissen, wie du es am saubersten hinbekommst deinen Threat mit Informationen zu Füttern.
Du könntest ja einfach in deiner Main-Funktion einen Pointer auf ein common_settings struct, also ein struct wo ALLE einstellungen, Pointer auf Parameter wenne s sich lohnt, etc. drinn isnd, disen Pointer übergibst du dann deiner Threat Funktion und diese sucht sich seine Parameter heraus.
Das common_settings struct zerstörst du dann beim BEENDEN des programms.
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Übergabe mehrerer Argumente an einen SDL_Thread

Beitrag von fat-lobyte » Di Apr 14, 2009 3:59 pm

cloidnerux hat geschrieben:Wie es aussieht, willst du einfach nur wissen, wie du es am saubersten hinbekommst deinen Threat mit Informationen zu Füttern.
Du könntest ja einfach in deiner Main-Funktion einen Pointer auf ein common_settings struct, also ein struct wo ALLE einstellungen, Pointer auf Parameter wenne s sich lohnt, etc. drinn isnd, disen Pointer übergibst du dann deiner Threat Funktion und diese sucht sich seine Parameter heraus.
Das common_settings struct zerstörst du dann beim BEENDEN des programms.
Das ist keine Gute Idee. Erstens löst du damit keine Probleme, da du genauso ein Struct übergeben musst, nur eben ein größeres.
Zweitens widerspricht das gutem Programmierstil, denn man sollte Unterfunktionen und Unterklassen nur die Information und zugriffsrechte geben, die unbedingt notwendig sind. Das nennt man "Kapselung".

Wenn du das nicht tust, und einfach alle Variablen in ein Riesen struct schmeißt kommts auf das gleiche Raus, wie wenn du alle Variablen global deklarieren würdest. Du kommst durcheinander, weißt nicht mehr welche Variable wohin gehört und wozu sie gut ist.
Kurz gesagt: schlechte Idee.
Haters gonna hate, potatoes gonna potate.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3123
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Übergabe mehrerer Argumente an einen SDL_Thread

Beitrag von cloidnerux » Di Apr 14, 2009 4:01 pm

Kurz gesagt: schlechte Idee.
War nur eine Idee, nichts was ich nutzen würde.
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Übergabe mehrerer Argumente an einen SDL_Thread

Beitrag von Dirty Oerti » Mi Apr 15, 2009 9:15 pm

fat-lobyte hat geschrieben:Tag zurück.
:)
Kerli hat geschrieben:Davon habe ich eigentlich noch nie gehört. Aber durch die Hardware wird es wahrscheinlich schon eine Beschränkung geben. Es bekommt zb jeder Thread einen gewissen Platz im Arbeitsspeicher für seinen Stack.
fat-lobyte hat geschrieben:190 Threads ?!? Was zur hölle hast du vor? Ne Armee von Zombifunktionen zu schreiben und damit ne Bank zu überfallen?

Ich sags ungern, aber die Performance wird unter aller Sau sein. Schau:
Die CPU kann pro core genau einen Thread behandeln. Deswegen laufen Threads nur scheinbar gleichzeitig ab. Wenn die CPU von einem auf einen anderen Thread schaltet muss das Betriebssystem und die CPU nicht wenig Arbeit verrichten. Wenn du 190 Threads hast, glaubst du die CPU kommt noch zu was anderem als Threads umzuschalten?
Mir ist klar, dass 190 Threads recht heftig sind.
Im Endeffekt möchte ich eigenltich ja nur ein paar (3?) extra Threads.
Ich wollte nur mal eben gucken, was passiert, wenn ich versucht 30.000 Threads zu starten ;)
fat-lobyte hat geschrieben:Richtig. Darf ich fragen was du mit "thread killen" meinst? Heißt das du schickst ihm einen Interrupt? Einen thread einfach zu "töten" ist eine sehr schlechte idee. Du solltest in dem thread "exit points" einrichten, mit denen du den thread notfalls unterbrechen kannst.
Die SDL gibt mir eine Funktion, die nimmt als Parameter eine Thread und dann ist der aus. Wie genau das funktioniert weiß ich nicht. Ich nehme aber mal stark an, dass es sich dabei um "Töten" handelt.
fat-lobyte hat geschrieben:Ja. Und außerdem viel zu kompliziert und fehleranfällig.
Es funtioniert immerhin schon mal scheinbar. Aber es gefällt mir einfach nicht, zum Beenden von Threads neue Threads starten zu müssen...

fat-lobyte hat geschrieben:Auf jeden Fall.
Dachte ich mir schon :)
Ich hab nur leider kein Tutorial über Boost-Threads gefunden...
fat-lobyte hat geschrieben:shared_ptr halten einen Zeiger auf ein mit new allokiertes Objekt. Wenn alle shared_ptr, die auf dieses Objekt zeigen zerstört ist, wird auch das Objekt freigegeben.
Ja, das kenn ich. Soetwas benutzt OpenSceneGraph (was da auch mit reinspielt) ständig, nennt sich osg::ref_ptr<T>
Wie genau ich die Übergebe hab ich leider noch nicht rausgefunden.
cloidnerux hat geschrieben:Wie es aussieht, willst du einfach nur wissen, wie du es am saubersten hinbekommst deinen Threat mit Informationen zu Füttern.
Das ist richtig^^
Die 190 Threads sind natürlich nicht zweckdienlich^^
Da bräuchte ich schon einen Rechner mit vielen Prozessoren/Cores...


Nun nochmal dazu, wofür ich das brauche:
Ich hab mich mal wieder ein bisschen in die Spieleprogrammierung gewagt und will mit den Threads die Aufgaben zum Bearbeiten des SceneGraphen aus dem Thread abkapseln, der den Graphen zeichnet.
Außerdem soll evtl. Netzwerkfähigkeit in einen extra Thread kommen, so dass sich das nicht blockiert.

Und vorrangig wollte ich das halt erstmal hinbekommen^^ :)

[quote?"fat-lobyte"]Nutze doch boost threads!!
Die sind viel viel sauberer und klarer.
(...Code...)[/quote]
Da hast du Recht.
:) Ich werd nun mal mein Vorhaben mit BOOST realisieren.

MfG
Daniel
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Übergabe mehrerer Argumente an einen SDL_Thread

Beitrag von fat-lobyte » Do Apr 16, 2009 9:27 am

Dirty Oerti hat geschrieben: Die SDL gibt mir eine Funktion, die nimmt als Parameter eine Thread und dann ist der aus. Wie genau das funktioniert weiß ich nicht. Ich nehme aber mal stark an, dass es sich dabei um "Töten" handelt.
Bevor du das verwenden würdest, solltest du dich unbedingt schlau machen was genau das heißt, und nicht einfach annehmen. Genau solche annahmen führen zu Bugs die schwer nachzuvollziehen sind. Aber wie gesagt, Boost ist hier die bessere Wahl.
Dirty Oerti hat geschrieben:Ich hab nur leider kein Tutorial über Boost-Threads gefunden...
Wichtig ist, dass du schon eine Ahnung von Concurrent Programming hast. Lies dir erstmal irgendwas über Threads im allgemeinen durch. Wenn du das getan hast, gibts 2 Möglichkeiten:
a) Learning by doing: Einfach mal einsteigen, und Probieren. Natürlich musst du die referenz daneben liegen haben: http://www.boost.org/doc/libs/1_38_0/do ... hread.html
Ein paar beispiele sind normalerweise in der Distribution zu finden (entweder tarball runterladen oder -doc paket deiner Linuxdistribution installieren)
b) Es gibt ein Tutorial:
http://www.ddj.com/cpp/184401518
Achtung! Das ist ziemlich alt. Bitte erstens die Referenz hernehmen, und außerdem noch diesen Artikel: http://www.ddj.com/cpp/211600441
Dirty Oerti hat geschrieben:Ich werd nun mal mein Vorhaben mit BOOST realisieren.
Gute Entscheidung!
Haters gonna hate, potatoes gonna potate.

Antworten