Mehrere Argumente an Threads in C?
Markus Pitha
- programmiertechnik
Hallo,
Ich habe eine Funktion, die als neuer Thread laufen soll. Die Funktion sieht so aus:
void ball(SDL_Surface *bg, SDL_Surface *dplay);
Wenn ich nun aber einen Thread erzeugen will, kann ich das nicht, da ich nicht die Funktion inkl. Argumente, die die Funktion braucht, übergeben kann.
Daraufhin habe ich versucht die 2 von der ball Funktion benötigten Argumente dem 4. Argument der pthread_create Funktion zu übergeben (Prototyp: int pthread_create (pthread_t *th, pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); ) falls ich das richtig interpretiert habe.
Ich weiß aber nicht, wie ich 2 Argumente, die auch von anderen Typen sind der Funktion ball übergeben kann, da die thread_create Funktion an der 4. Stelle nur ein Argument entgegen nimmt. Wie stellt man so etwas an?
Markus.
你好 Markus,
Ich weiß aber nicht, wie ich 2 Argumente, die auch von anderen Typen sind
der Funktion ball übergeben kann, da die thread_create Funktion an der 4.
Stelle nur ein Argument entgegen nimmt. Wie stellt man so etwas an?
Erstelle eine Struktur, in der du die beiden Argumente speicherst. Dann
erstelle eine Wrapper-Struktur, die dann etwa so aussieht:
void *thread_ball(void *arg) {
struct my_arg_s *my_arg = (struct my_arg_s *)arg;
ball(my_arg->bg, my_arg->dplay);
return NULL;
}
再见,
克里斯蒂安
你好 Markus,
Erstelle eine Struktur, in der du die beiden Argumente speicherst. Dann
erstelle eine Wrapper-Struktur, die dann etwa so aussieht:
Muss natürlich heissen: Erstelle eine Wrapper-Funktion.
再见,
克里斯蒂安
Hi,
also irgendwie kommeich damit nicht klar.
Ich habe eine Struktur erzeugt:
struct ball {
SDL_Surface *background;
SDL_Surface *display;
} ballargs;
..dann habe ich die Variablen, die ich ursprünglich übergeben wollte den Variablen in der Struktur zugewiesen (wobei background und display Zeiger auf den Typ SDL_Surface sind):
ballargs.background = background;
ballargs.display = display;
..und alles dem Thread übergeben...
pthread_create(&thr1, NULL, thread_ball, &ballargs);
In der Funktion, die ich nun thread_ball genannt habe, nehme ich sie entgegen:
void *thread_ball(void *arg) {
struct ballargs *myarg = (struct ballargs *)arg;
Die Frage ist aber nun, wie ich meine Werte aus der Struktur wieder richtig herausbekomme?
Kombinationen von myarg.background, (*myarg).background, oder myarg->background
haben nichts gebracht. Das Programm lässt isch zwar kompilieren, aber es läuft nicht richtig. Offensichtlich irgend ein Zeigerfehler, da ich Xlib Fehlermeldungen in der Konsole bekomme, und die Grafiken tun eigentlich auch nicht das, was sie sollten.
Markus.
你好 Markus,
struct ball {
SDL_Surface *background;
SDL_Surface *display;
} ballargs;
Sieht schonmal gut aus.
..und alles dem Thread übergeben...
pthread_create(&thr1, NULL, thread_ball, &ballargs);
Was passiert mit background und display nach dem pthread_create-Aufruf?
In der Funktion, die ich nun thread_ball genannt habe, nehme ich sie
entgegen:
void *thread_ball(void *arg) {
struct ballargs *myarg = (struct ballargs *)arg;
Jupp, auch ok.
Die Frage ist aber nun, wie ich meine Werte aus der Struktur wieder
richtig herausbekomme?
über myarg->background bzw. myarg->display.
Das Programm lässt isch zwar kompilieren, aber es läuft nicht richtig.
Siehe dazu meine Frage weiter oben. Ausserdem musst du daran denken, dass
du mit myarg->background bzw. myarg->display Pointer auf SDL_Surface
bekommst. Wenn du also die Funktion ball aufrufst, darfst du sie nicht
nochmal referenzieren:
ball(myarg->background, myarg->display)
Wenn du noch einen Referenzierungs-Operator davor packen würdest
(&myarg->background z. B.), dann hättest du nicht mehr SDL_Surface *,
sondern SDL_Surface **.
Ansonsten musst du schon etwas mehr Code zeigen. Fehlersuche ist so
schwierig.
再见,
克里斯蒂安
Hallo,
pthread_create(&thr1, NULL, thread_ball, &ballargs);
Was passiert mit background und display nach dem pthread_create-Aufruf?
Das ist irgendwie das, was ich herausfinden will. Ab hier stelle ich es mir so vor, dass die Funktion thread_ball nun die Argumente übernommen hat, was sie wahrscheinlich auch getan hat, da ich die Grafiken sehen konnte.
Die Frage ist aber nun, wie ich meine Werte aus der Struktur wieder
richtig herausbekomme?über myarg->background bzw. myarg->display.
Das Programm lässt sich zwar kompilieren, aber es läuft nicht richtig.
Siehe dazu meine Frage weiter oben. Ausserdem musst du daran denken, dass
du mit myarg->background bzw. myarg->display Pointer auf SDL_Surface
bekommst. Wenn du also die Funktion ball aufrufst, darfst du sie nicht
nochmal referenzieren:
ball(myarg->background, myarg->display)
Das verstehe ich leider nicht. Die Funktion ball habe ich nach thread_ball umbenannt und wo genau ist diese Verwendung ball(myarg->background, myarg->display) gedacht?
Ich poste mal das File, um vielleicht einen besseren Überblick zu verschaffen.
Durch das Verschieben der einzelnen Zeilen ist es leider nicht so ganz übersichtlich.
http://test.pithax.net/main.c
Diese Funktion funktioniert nun nicht. Ich bekomme beim Kompilieren durch die letzten Zeilen eine Fehlermeldung, dass ich einen Pointer zu einem inkompatiblen Typ dereferenziere.
Markus
http://test.pithax.net/main.c
Diese Funktion funktioniert nun nicht.
"Dieses File" wollte ich sagen.
Markus.
你好 Markus,
Du hattest ein paar Fehler drin, unter anderem einen in der
struct-Definition. Einen struct definiert man so:
struct ball_s {
SDL_Surface *display,*background;
};
Was du gemacht hast, war einen Struct ball zu definieren und dann eine
Variable ballargs anzulegen ;-) Hier ist mal die verbesserte Version (waren
sonst noch ein paar kleine Flüchtigkeitsfehler drin):
Ausserdem hab ich mal indent drüberlaufen lassen, damit man eine
vernünftige Formatierung hat... *g*
再见,
克里斯蒂安
Hi,
danke für die Hilfe. Allerdings habe ich jetzt genau das Problem, das ich schon mal hatte. Die Grafiken bewegen sich kaum, sie hängen irgendwie. (Die Maussteuerung funktioniert auch nicht) und in der Konsole erscheinen wieder Xlib Fehlermeldungen.
zB Xlib: unexpected async reply sequence (0xaa6)
Ich kann das Programm dann nur schließen, wenn ich die Konsole beende.
Es liegt definitiv an den Threads, nur weiß ich gar nicht, wo der Fehler liegen könnte? Ohne dem Thread würde sich nur der Ball bewegen, und die Grafik mit der Maussteuerung nicht (was auch logisch ist).
Markus.
你好 Markus,
Es liegt definitiv an den Threads, nur weiß ich gar nicht, wo der Fehler
liegen könnte? Ohne dem Thread würde sich nur der Ball bewegen, und die
Grafik mit der Maussteuerung nicht (was auch logisch ist).
Kannst du mal die Grafiken bereitstellen? So kann man sich da schwer
reinarbeiten.
再见,
克里斯蒂安
Hi,
Kannst du mal die Grafiken bereitstellen? So kann man sich da schwer
reinarbeiten.
gerne.
http://test.pithax.net/grafiken/
Hier auch die Version mit noch keinem existierenden Thread.
http://test.pithax.net/main_ohne_threads.c
P.S Die Gänsefüsschen bei den Headerdateien sind Absicht, da ich die Bibliotheken dynamisch verlinke. Ich weise nur darauf hin, da du mir es bei deiner Version ausgebessert hast.
Markus.
你好 Markus,
so, Fehler gefunden. Eigentlich warens zwei.
Die Threads greifen (quasi) gleichzeitig auf Ressourcen (in diesem Fall
wohl der Video-Speicher) zu, wo sie nur einzeln drauf zugreifen dürfen.
Die Lösung ist Synchronisation, z. B. mit einem Mutex. Ich habe die
geänderte Version an derselben Stelle nochmal hochgeladen.
Du hast zig Threads gestartet, die alle noch weiterliefen. Das ist
poehse, lastet das System völlig aus, vor allem habe ich den Eindruck,
das wolltest du gar nicht so. Ich habe es jetzt so umgebaut, dass der
Thread am Anfang gestartet wird und dann parallel zum Haupt-Thread
läuft und die Kugel bewegt.
P.S Die Gänsefüsschen bei den Headerdateien sind Absicht, da ich die
Bibliotheken dynamisch verlinke. Ich weise nur darauf hin, da du mir es
bei deiner Version ausgebessert hast.
Mag ja sein, aber sie sind falsch :) Strengere Compiler würden es dir um
die Ohren hauen. Und dynamisch oder statisch linken hat nichts damit zu
tun, wie du die Header-Dateien einbindest. der Unterschied zwischen
#include <> und #include "" ist subtiler: bei #include <> wird die
Header-Datei im Standard-Include-Pfad gesucht, bei #include "" im aktuellen
Pfad bzw. in weiteren Pfaden, die man per Compiler-Switch dazuschauten
kann (-I- -I/weiter/pfad). Ob du jetzt dynamisch linkst oder statisch ist
dabei völlig ohne Interesse.
再见,
克里斯蒂安
Hallo,
Vielen dank. Das mit dem Grafikspeicher hätte ich weder erraten, noch hätte ich gewusst, wie ich das Problem lösen hätte sollen.
Threads sind ja auch Neuland für mich. :)
P.S Nur so nebenbei: Der Ball braucht immer ca 1. Sek bis er losfliegt nachdem das Programm gestartet wurde. Weißt du zufällig warum das so ist? Am Code konnte ich nichts erkennen, aber mit den Mutexen hängt es auch nicht zusammen (zumindest habe ich auf die Eile nichts gefunden, was in Verbindung mit Mutexen damit zusammenhängt). Das Delay am Schluss ist es übrigens auch nicht.
Markus.
你好 Markus,
P.S Nur so nebenbei: Der Ball braucht immer ca 1. Sek bis er losfliegt
nachdem das Programm gestartet wurde. Weißt du zufällig warum das so ist?
Vermutlich liegt das am Scheduler. Du hast ja nur eine
Single-Prozessor-Maschine (davon gehe ich jetzt einfach mal aus) zur
Verfuegung, das heisst, der Scheduler stellt jedem Thread nur ein bestimmtes
Quantum an CPU-Zeit zur Verfuegung. Wann also ein Thread aktiv wird, ist
nicht definiert; es kann theoretisch auch sein, dass er erst nach 10
Sekunden aktiviert wird. Wenn du garantierte Reaktionszeiten haben
möchtest, benutze ein anderes Scheduler-Verfahren (man
pthread_setschedparam).
Vermutlich reicht es in diesem Fall aber pthread_yield() direkt nach dem
pthread_create() aufzurufen (das legt den aufrufenden Thread für einige
Zyklen schlafen).
Wenn dich Thread-Programmierung interessiert, kann ich dir das Buch
“Programming with POSIX Threads” empfehlen:
http://www.amazon.de/exec/obidos/ASIN/0201633922/
Wenn du das Buch durchgearbeitet hast, sollte Thread-Programmierung (egal
in welcher Sprache) kein grosses Problem mehr fuer dich darstellen.
再见,
克里斯蒂安
Hallo,
Vermutlich liegt das am Scheduler. [...]
Alles klar.
Wenn dich Thread-Programmierung interessiert, kann ich dir das Buch
“Programming with POSIX Threads” empfehlen:
http://www.amazon.de/exec/obidos/ASIN/0201633922/
Tja. Bei mir geht es weniger ums Interesse als um die Zeit, die ich leider nicht habe :(
P.S Eher erstaunlicher finde ich allerdings, dass es nicht mal vernüftige Tutorials über SDL gibt. All die verfügbaren Kurztutorials beinhalten lediglich die Grundfunktionen, sowie einige grundlegende Beispiele, die aber auch oft nur ein wenig "geschummelt" sind. (zB Probleme des Auffrischens einzelner Grafiken werden einfach durchgeschummelt indem einfach der ganze Screen anstatt einem sauberen "Blitten" neu refresht wird, oder es wird so refresht, dass die Grafiken bei Bewegungen zu flackern beginnen, also mit einem Wort falsch.)
Markus.
你好 Markus,
Wenn dich Thread-Programmierung interessiert, kann ich dir das Buch
“Programming with POSIX Threads” empfehlen:
http://www.amazon.de/exec/obidos/ASIN/0201633922/Tja. Bei mir geht es weniger ums Interesse als um die Zeit, die ich
leider nicht habe :(
Ist eine gute Bett-Lektuere... ;-)
P.S Eher erstaunlicher finde ich allerdings, dass es nicht mal vernüftige
Tutorials über SDL gibt. All die verfügbaren Kurztutorials beinhalten
lediglich die Grundfunktionen, sowie einige grundlegende Beispiele, die
aber auch oft nur ein wenig "geschummelt" sind.
Das ist typisch fuer Bibliotheken und Programme aus der *NIX-Welt. Es wird
erwartet, dass man sich bei tiefergehender Beschaeftigung mit der Materie
das Wissen selbst aneignet und anarbeitet. Die meisten Tutorials dienen
dazu, einen Einstieg zu finden, mehr aber auch nicht.
再见,
克里斯蒂安