pthread_create und Übergabe einer Ganzzahl als letztes Argument

Lesezeit: 8 Minuten

Benutzeravatar von Gradient
Gradient

Ich habe folgende Funktionen:

void *foo(void *i) {
    int a = (int) i;
}

int main() {
    pthread_t thread;
    int i;
    pthread_create(&thread, 0, foo, (void *) i);
}

Beim Kompilieren gibt es einige Fehler beim Casting ((void *) i und int a = (int) i). Wie kann ich eine Ganzzahl als letztes Argument von übergeben pthread_create richtig?

Crowmans Benutzeravatar
Krähenmann

Aufbauend auf der Antwort von szx (geben Sie ihm also die Anerkennung), so würde es bei Ihnen funktionieren for Schleife:

void *foo(void *i) {
    int a = *((int *) i);
    free(i);
}

int main() {
    pthread_t thread;
    for ( int i = 0; i < 10; ++1 ) {
        int *arg = malloc(sizeof(*arg));
        if ( arg == NULL ) {
            fprintf(stderr, "Couldn't allocate memory for thread arg.\n");
            exit(EXIT_FAILURE);
        }

        *arg = i;
        pthread_create(&thread, 0, foo, arg);
    }

    /*  Wait for threads, etc  */

    return 0;
}

Bei jeder Iteration der Schleife weisen Sie neuen Speicher zu, jeder mit einer anderen Adresse, also dem Ding, an das weitergegeben wird pthread_create() bei jeder Iteration ist anders, sodass keiner Ihrer Threads versucht, auf denselben Speicher zuzugreifen, und Sie erhalten keine Thread-Sicherheitsprobleme in der Art und Weise, wie Sie es tun würden, wenn Sie nur die Adresse von übergeben würden i. In diesem Fall könnte man auch ein Array aufbauen und die Adressen der Elemente übergeben.

  • Ich bekomme das, wenn ich kompiliere: error: invalid conversion from ‘void*’ to ‘int*’ in dieser Zeile: int *arg = malloc(sizeof(*arg));. Sie sollten (int *) vor malloc setzen.

    – Gefälle

    8. Oktober 2013 um 0:35 Uhr


  • @Gradient: Sie müssen dies als C++ kompilieren. Die Besetzung ist in C nicht erforderlich und sollte meiner Meinung nach nicht enthalten sein.

    – Krähenmann

    8. Oktober 2013 um 0:38 Uhr

  • Ich glaube der Aussage int *arg = malloc(sizeof(*arg)); sollte stattdessen sein int *arg = malloc(sizeof(arg));. Hier funktioniert es, weil ein Zeiger auf den meisten Maschinen die Größe von int hat. Es kann jedoch bei anderen Datentypen oder sogar benutzerdefinierten Typen fehlschlagen. Korrigiert mich, wenn ich hier falsch liege

    – HighOnMeat

    11. Februar 2015 um 15:36 Uhr


  • @Pegasus: Du liegst falsch. Hier möchten Sie die richtige Menge an Speicherplatz für eine zuweisen intnicht für einen Zeiger auf int. Ihre Alternative würde Letzteres tun, also ist es eigentlich Ihr Vorschlag, der nur funktionieren würde, wenn Zeiger und ints sind gleich groß.

    – Krähenmann

    11. Februar 2015 um 17:48 Uhr

  • @Pegasus: Nein, es weist Platz für ein zu int. int * arg = malloc(sizeof(&arg)); würde Platz für einen Zeiger auf den Zeiger zuweisen int. Wenn Sie “nicht überzeugt” sind, dann sind Sie nur verwirrt über die grundlegende C-Syntax.

    – Krähenmann

    12. Februar 2015 um 11:57 Uhr


Sie können eine zuweisen int auf den Haufen und weitergeben pthread_create(). Sie können es dann in Ihrer Thread-Funktion freigeben:

void *foo(void *i) {
    int a = *((int *) i);
    free(i);
}

int main() {
    pthread_t thread;
    int *i = malloc(sizeof(*i));
    pthread_create(&thread, 0, foo, (void *) i);
}

  • Wie ich in einer anderen Antwort sagte: Ich bin mir nicht sicher, ob diese Lösung funktioniert. Bis der erste Thread reicht int a = *((int *) i)die for-Schleife könnte den Wert von geändert haben i. Also, wenn der erste Thread versucht zu initialisieren a, würde es nicht den richtigen Wert lesen. Oder vielleicht bin ich mit dem Konzept der Threads verwirrt?

    – Gefälle

    7. Oktober 2013 um 22:46 Uhr

  • @Gradient: Ihr anderer Kommentar war richtig, aber das passiert hier nicht. Diese Lösung weist jedem Thread neuen Speicher für das Argument zu (oder zumindest, wenn Sie es in eine Schleife einfügen, würden Sie in jeder Schleife neuen Speicher zuweisen), sodass jeder Thread ein anderes Objekt erhält und keine zwei Threads versuchen, darauf zuzugreifen gleiche Erinnerung. Sie verstehen das Konzept der Threads richtig, diese Lösung weist das von Ihnen erwähnte Problem einfach nicht auf. Ich denke, diese Lösung würde verbessert, indem tatsächlich gezeigt würde, wie sie in einer Schleife funktionieren würde.

    – Krähenmann

    7. Oktober 2013 um 22:48 Uhr


Benutzeravatar von PP
PP

Sie sollten die Adresse von werfen i (anstelle des Wertes von i wie Sie es jetzt tun) im letzten Argument von pthread_create().

pthread_create(&thread, 0, foo, (void *) &i);
                                         ^  is missing

Und auch in deiner Funktion ist das Casting falsch. Es sollte sein:

int a = *((int*) i);
  1. Wenn Sie es beabsichtigen lesen den Wert sollten Sie ebenfalls initialisieren i auf einen Wert in main(), da es jetzt nicht initialisiert ist.

2 Verwenden Sie die richtige Definition für main():

 int main(void) 

oder int main(int argc, char *argv[]) oder sein Äquivalent.

  • Funktioniert das ggf i wird in a erklärt for Schleife? Zum Beispiel for (int i=0;...;...) Oder sollte ich es vorher deklarieren for Schleife?

    – Gefälle

    7. Oktober 2013 um 21:13 Uhr

  • Das Deklarieren in einer for-Schleife ist nicht anders und würde auf die gleiche Weise funktionieren. Das Deklarieren von Variablen in einer for-Schleife ist jedoch nur im C99-Modus (oder höher) zulässig. Sie müssten mit kompilieren -std=c99 zum Beispiel zusammen mit anderen Compiler-Optionen.

    – PP

    7. Oktober 2013 um 21:22 Uhr

  • Auch wenn ich es tue &idann gebe ich dem Thread die Adresse der Variablen i. Wenn ich andere Threads erstelle, würde ich das nicht tun i von allen Threads geteilt werden? Das wäre nicht das gewünschte Verhalten.

    – Gefälle

    7. Oktober 2013 um 21:26 Uhr


  • Ich bin mir nicht sicher, ob die zweite Lösung funktionieren würde. Bis dahin reicht der erste Thread int a = *((int *) i)die for-Schleife könnte den Wert von geändert haben i. Also, wenn der erste Thread versucht zu initialisieren awürde es nicht den richtigen Wert lesen.

    – Gefälle

    7. Oktober 2013 um 22:06 Uhr

  • @Gradient: Sie haben Recht, das Übergeben der Adresse der Schleifenvariablen ist nicht garantiert sicher. Die Ergebnisse des Gießens an int zu einem Zeiger und zurück sind implementierungsdefiniert, daher ist dies auch keine großartige Lösung. Verwenden malloc() ist der beste Weg.

    – Krähenmann

    7. Oktober 2013 um 22:47 Uhr

Benutzeravatar von Jerska
Jerska

Alte Frage, aber ich stand heute vor dem gleichen Problem und habe mich entschieden, diesen Weg nicht zu gehen. Bei meiner Anwendung ging es wirklich um Leistung, also entschied ich mich für diese Reihe von ints statisch deklariert.

Da ich nicht viele Anwendungen kenne, wo Ihre pthread_join / pthread_cancel ist in einem anderen Bereich als Ihrem pthread_createIch habe mich für diesen Weg entschieden:

#define NB_THREADS 4

void *job(void *_i) {
  unsigned int i = *((unsigned int *) _i);
}

int main () {
  unsigned int ints[NB_THREADS];
  pthread_t    threads[NB_THREADS];
  for (unsigned int i = 0; i < NB_THREADS; ++i) {
    ints[i] = i;
    pthread_create(&threads[i], NULL, job, &ints[i]);
  }
}

Ich finde es eleganter, effizienter, und Sie müssen sich keine Sorgen um die Befreiung machen, da es nur in diesem Bereich lebt.

Obwohl dies eine alte Frage ist, fehlt eine Option, wenn Sie nur eine positive ganze Zahl wie einen Deskriptor übergeben müssen: Sie können sie direkt als Adresse übergeben, während es sich um einen Hack handelt, funktioniert sie gut und vermeidet die Zuweisung von irgendetwas 🙂

HINWEIS: Die Größe der Ganzzahl muss mit der Größe eines Zeigers auf Ihrem Betriebssystem übereinstimmen, aber heutzutage sind die meisten Systeme native 64-Bit-Systeme.

#include <pthread.h>
#include <inttypes.h>
#include <stdio.h>

void *_thread_loop(void *p)
{
  uint64_t n = (uint64_t)p;

  printf("received %llu\n", n);

  return NULL;
}



int main(int argc, char const *argv[])
{
  pthread_t read_thread_id;
  uint64_t n = 42;
  pthread_create(&read_thread_id, NULL, _thread_loop, (void *)n);

  pthread_join(read_thread_id, NULL);
  return 0;
}

  • Laut dieser Antwort ist das Ergebnis dieses Hacks implementierungsdefiniert und (im Allgemeinen) nicht portierbar.

    – tonysdg

    16. Januar 2018 um 13:54 Uhr

  • Ich bin mir nicht ganz sicher, ob die von Ihnen verlinkte Antwort wirklich bedeutet, dass das Ergebnis möglicherweise nicht auf gültige Daten verweist, und das ist offensichtlich (der Zeiger wird niemals dereferenziert), aber bisher hatte ich nie Probleme damit, ich habe keine getestet exotische architekturen funktionierten aber für mich unter linux auf x86 und am64 sowie arm (auf einem raspberrypi).

    – Schmurfi

    28. Januar 2018 um 19:13 Uhr

  • Oh, ich bezweifle sehr, dass Sie jemals Probleme damit haben werden, es sei denn, Sie laufen auf einem Ja wirklich exotische Architektur 🙂 Und dieser Hack hat bei mehr als ein paar Gelegenheiten für mich funktioniert. Ich poste nur der Vollständigkeit halber!

    – tonysdg

    30. Januar 2018 um 0:08 Uhr

  • Laut dieser Antwort ist das Ergebnis dieses Hacks implementierungsdefiniert und (im Allgemeinen) nicht portierbar.

    – tonysdg

    16. Januar 2018 um 13:54 Uhr

  • Ich bin mir nicht ganz sicher, ob die von Ihnen verlinkte Antwort wirklich bedeutet, dass das Ergebnis möglicherweise nicht auf gültige Daten verweist, und das ist offensichtlich (der Zeiger wird niemals dereferenziert), aber bisher hatte ich nie Probleme damit, ich habe keine getestet exotische architekturen funktionierten aber für mich unter linux auf x86 und am64 sowie arm (auf einem raspberrypi).

    – Schmurfi

    28. Januar 2018 um 19:13 Uhr

  • Oh, ich bezweifle sehr, dass Sie jemals Probleme damit haben werden, es sei denn, Sie laufen auf einem Ja wirklich exotische Architektur 🙂 Und dieser Hack hat bei mehr als ein paar Gelegenheiten für mich funktioniert. Ich poste nur der Vollständigkeit halber!

    – tonysdg

    30. Januar 2018 um 0:08 Uhr

1403940cookie-checkpthread_create und Übergabe einer Ganzzahl als letztes Argument

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy