Markus Pitha: Mehrere Argumente an Threads in C?

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.

--
sh:( fo:| ch:? rl:( br:> n4:( ie:{ mo:) va:) de:] zu:) fl:( ss:| ls:] js:|
  1. 你好 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;  
    }  
    
    

    再见,
    克里斯蒂安

    --
    89,7% aller Statistiken sind frei erfunden!
    http://wwwtech.de/
    1. 你好 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.

      再见,
      克里斯蒂安

      --
      lim(3->4)(sqrt(3)) = 2
      http://wwwtech.de/
    2. 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.

      --
      sh:( fo:| ch:? rl:( br:> n4:( ie:{ mo:) va:) de:] zu:) fl:( ss:| ls:] js:|
      1. 你好 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.

        再见,
        克里斯蒂安

        --
        Der Mund ist das Portal zum Unglück.
        http://wwwtech.de/
        1. 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

          --
          sh:( fo:| ch:? rl:( br:> n4:( ie:{ mo:) va:) de:] zu:) fl:( ss:| ls:] js:|
          1. http://test.pithax.net/main.c
            Diese Funktion funktioniert nun nicht.

            "Dieses File" wollte ich sagen.

            Markus.

            --
            sh:( fo:| ch:? rl:( br:> n4:( ie:{ mo:) va:) de:] zu:) fl:( ss:| ls:] js:|
          2. 你好 Markus,

            [...]
            http://test.pithax.net/main.c

            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):

            http://www.defunced.de/ball.c

            Ausserdem hab ich mal indent drüberlaufen lassen, damit man eine
            vernünftige Formatierung hat... *g*

            再见,
            克里斯蒂安

            --
            Die Wirklichkeit hat weder ein Inneres, noch ein Äußeres, noch ein Zentrum.
            http://wwwtech.de/
            1. 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.

              --
              sh:( fo:| ch:? rl:( br:> n4:( ie:{ mo:) va:) de:] zu:) fl:( ss:| ls:] js:|
              1. 你好 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.

                再见,
                克里斯蒂安

                --
                Zu wissen, was wir nicht wissen, ist die Quelle der Weisheit.
                http://wwwtech.de/
                1. 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.

                  --
                  sh:( fo:| ch:? rl:( br:> n4:( ie:{ mo:) va:) de:] zu:) fl:( ss:| ls:] js:|
                  1. 你好 Markus,

                    so, Fehler gefunden. Eigentlich warens zwei.

                    1. 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.

                    2. 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.

                    再见,
                    克里斯蒂安

                    --
                    Ihr wisst nicht, wie man den Menschen dient. Wie sollt ihr wissen, wie man den Goettern dienen soll?
                    http://wwwtech.de/
                    1. 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.

                      --
                      sh:( fo:| ch:? rl:( br:> n4:( ie:{ mo:) va:) de:] zu:) fl:( ss:| ls:] js:|
                      1. 你好 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.

                        再见,
                        克里斯蒂安

                        --
                        Death is God's way of telling you not to be such a wise guy.
                        http://wwwtech.de/
                        1. 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.

                          --
                          sh:( fo:| ch:? rl:( br:> n4:( ie:{ mo:) va:) de:] zu:) fl:( ss:| ls:] js:|
                          1. 你好 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.

                            再见,
                            克里斯蒂安

                            --
                            Keine Schneeflocke faellt je auf die falsche Stelle.
                            http://wwwtech.de/