Wie gebe ich einen Wert von pthread-Threads in C zurück?

Lesezeit: 8 Minuten

Benutzeravatar von Petr Peller
Peter Peller

Ich bin neu in C und würde gerne ein bisschen mit Threads spielen. Ich möchte einen Wert aus einem Thread mit zurückgeben pthread_exit()

Mein Code ist wie folgt:

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

void *myThread()
{
   int ret = 42;
   pthread_exit(&ret);
}

int main()
{
   pthread_t tid;
   void *status;
 
   pthread_create(&tid, NULL, myThread, NULL);
   pthread_join(tid, &status);

   printf("%d\n",*(int*)status);   
 
   return 0;
}

Ich würde die Programmausgabe erwarten "42\n" aber es gibt eine Zufallszahl aus. Wie kann ich den zurückgegebenen Wert drucken?

Es scheint ein Problem zu sein, dass ich einen Zeiger auf eine lokale Variable zurückgebe. Was ist die beste Methode zum Zurückgeben/Speichern von Variablen mehrerer Threads? Eine globale Hash-Tabelle?

  • Als Antwort auf die Bearbeitung: Ich würde eher ein Array verwenden, wenn ich mehreren Threads jeweils einen Ort zum Schreiben ihrer Ergebnisse bereitstellen müsste. Wenn Sie im Voraus keine Obergrenze für die Anzahl der zu erstellenden Threads kennen, würde ich dies normalerweise als Problem betrachten. Aber im Allgemeinen ist jede Struktur in Ordnung, solange derjenige, der den Thread startet, sicherstellen kann, dass es einen Ort gibt, an dem der Thread sein Ergebnis speichern kann. dem Thread wird mitgeteilt, wo er gespeichert werden soll; und wer sich dem Thread anschließt, kann das Ergebnis wiederherstellen und gegebenenfalls freigeben. Wenn der Thread mit dem gleichen Wert endet, den er als Parameter übergeben hat, kann das helfen.

    – Steve Jessop

    12. Februar 2010 um 12:08 Uhr


  • Für mich funktioniert das gut. In den letzten 12 Jahren hat sich einiges geändert.

    – vj

    25. Februar um 9:16 Uhr

Hier ist eine richtige Lösung. In diesem Fall wird tdata im Hauptthread zugewiesen, und es gibt Platz für den Thread, um sein Ergebnis zu platzieren.

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

typedef struct thread_data {
   int a;
   int b;
   int result;

} thread_data;

void *myThread(void *arg)
{
   thread_data *tdata=(thread_data *)arg;

   int a=tdata->a;
   int b=tdata->b;
   int result=a+b;

   tdata->result=result;
   pthread_exit(NULL);
}

int main()
{
   pthread_t tid;
   thread_data tdata;

   tdata.a=10;
   tdata.b=32;

   pthread_create(&tid, NULL, myThread, (void *)&tdata);
   pthread_join(tid, NULL);

   printf("%d + %d = %d\n", tdata.a, tdata.b, tdata.result);   

   return 0;
}

  • Dies ist das sauberste Beispiel hier – ich bin überrascht, dass es nicht höher bewertet wird. Insbesondere zeigt es, dass die Verwaltung des Speichers auf der aufrufenden Ebene richtig ist – und dass der Zeiger auch verwendet werden kann, um komplexere Strukturen zu übergeben – sowohl rein als auch raus.

    – Flori

    11. April 2017 um 13:03 Uhr


  • Was ist mit free() und Threads, die in einer for-Schleife warten?

    – Acauã Pitta

    6. Juli um 5:27

Sie geben die Adresse einer lokalen Variablen zurück, die nicht mehr vorhanden ist, wenn die Thread-Funktion beendet wird. In jedem Fall, warum anrufen pthread_exit? Warum nicht einfach einen Wert aus der Thread-Funktion zurückgeben?

void *myThread()
{
   return (void *) 42;
}

und dann hauptsächlich:

printf("%d\n", (int)status);   

Wenn Sie einen komplizierten Wert einer solchen Struktur zurückgeben müssen, ist es wahrscheinlich am einfachsten, ihn dynamisch über zuzuweisen malloc() und einen Zeiger zurückgeben. Natürlich ist dann der Code, der den Thread initiiert hat, für die Freigabe des Speichers verantwortlich.

  • Wenn Sie tatsächlich “warum nicht” meinen, dann liegt der Grund dafür darin, dass das Umwandeln von 42 in einen Zeigertyp ein undefiniertes Verhalten ist. Natürlich, wenn es etwas Schlechtes macht, dann ist es einer dieser “es ist eine C-Implementierung, Jim, aber nicht so, wie wir es kennen”-Momente.

    – Steve Jessop

    12. Februar 2010 um 11:49 Uhr

  • Das funktioniert, aber ich verstehe nicht wie. Was bedeutet die Besetzung (void*)? Ich mache einen Zeiger aus der Zahl 42 und werfe ihn dann zurück in int? Hat es Nachteile? Schließlich, wofür ist pthread_exit() gut, wenn ich einfach zurückgeben kann?

    – Peter Peller

    12. Februar 2010 um 11:52 Uhr

  • pthread_exit ist wie exit. Es ermöglicht Ihrem Thread ein frühes Aussteigen auf die gleiche Weise wie ein Programm ein vorzeitiges Aussteigen kann, und es kann von jedem Code im Thread aufgerufen werden, während Sie zum Zurückkehren zum Thread-Einstiegspunkt zurückkehren müssen. Der Unterschied besteht natürlich darin, dass Sie in einem Thread höchstwahrscheinlich überall Ressourcen verlieren, wenn Sie versuchen, ihn zu verlassen, anstatt ihn durch den Einstiegspunkt zu verlassen.

    – Steve Jessop

    12. Februar 2010 um 12:02 Uhr


  • Gießen 42 to void * ist nicht UB. Es ist implementierungsdefiniert. Und reale Implementierungen definieren es wie erwartet.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    24. Mai 2011 um 2:17 Uhr


  • Das Ergebnis könnte jedoch eine Trap-Darstellung sein. Ich bin in zweierlei Hinsicht vorsichtig mit Fallen. Erstens denke ich, dass es ziemlich vernünftig ist, einfach keinen Code zu schreiben, der sie lesen könnte, selbst auf eine Weise, von der argumentiert werden könnte, dass der Standard dies zulässt, weil der relevante Text nur lvalues ​​erwähnt. Zweitens ignoriere ich die Tatsache, dass im wirklichen Leben keine Implementierung ihre Typen so definiert, dass sie irgendwelche haben, außer vielleicht Fließkommatypen. Auf der gleitenden Skala vom Verlassen nur auf den Standard über die gängige Implementierungspraxis bis hin zu falschen Annahmen, die beißen, ist es eine ziemlich sichere Sache, in beiden Fällen weniger vorsichtig zu sein.

    – Steve Jessop

    30. Mai 2012 um 21:28 Uhr


Benutzeravatar von Steve Jessop
Steve Jessop

Sie haben einen Zeiger auf eine lokale Variable zurückgegeben. Das ist schlecht, auch wenn Threads nicht beteiligt sind.

Der übliche Weg, dies zu tun, wenn der Thread, der startet, derselbe Thread ist, der beitritt, wäre, einen Zeiger auf ein int an einem vom Aufrufer verwalteten Speicherort als vierten Parameter von pthread_create zu übergeben. Dies wird dann zum (einzigen) Parameter für den Einstiegspunkt des Threads. Sie können (wenn Sie möchten) den Thread-Exit-Wert verwenden, um den Erfolg anzuzeigen:

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

int something_worked(void) {
    /* thread operation might fail, so here's a silly example */
    void *p = malloc(10);
    free(p);
    return p ? 1 : 0;
}

void *myThread(void *result)
{
   if (something_worked()) {
       *((int*)result) = 42;
       pthread_exit(result);
   } else {
       pthread_exit(0);
   }
}

int main()
{
   pthread_t tid;
   void *status = 0;
   int result;

   pthread_create(&tid, NULL, myThread, &result);
   pthread_join(tid, &status);

   if (status != 0) {
       printf("%d\n",result);
   } else {
       printf("thread failed\n");
   }

   return 0;
}

Wenn Sie unbedingt den Thread-Exit-Wert für eine Struktur verwenden müssen, müssen Sie ihn dynamisch zuweisen (und sicherstellen, dass jeder, der dem Thread beitritt, ihn freigibt). Das ist aber nicht ideal.

  • Ich habe das gerade herausgefunden, aber gem pubs.opengroup.org/onlinepubs/9699919799/functions/… Sie müssen pthread_exit nicht in Ihrem Funktionsaufruf für den Thread verwenden. “Der normale Mechanismus, durch den ein Thread beendet wird, besteht darin, von der Routine zurückzukehren, die in dem Aufruf pthread_create() angegeben wurde, der ihn gestartet hat. Die Funktion pthread_exit() bietet die Möglichkeit, einen Thread zu beenden, ohne dass eine Rückkehr von der Startroutine von erforderlich ist diesem Thread, wodurch eine Funktion analog zu exit() bereitgestellt wird.” Zur vorzeitigen Beendigung sollte pthread_exit verwendet werden.

    – Zachary Kraus

    27. August 2014 um 4:05 Uhr

  • printf ("thread failed\n"); – Ich würde stattdessen den Fehler ausdrucken stderr verwenden fprintf.

    – Kiste Kiste Kiste Kiste

    28. Dezember 2015 um 5:56 Uhr

  • vergleichen void * status zu int null führt zu “Warnung: Vergleich zwischen Zeiger und Ganzzahl”

    – VeraKozya

    15. Juli 2019 um 23:39 Uhr

  • @ Steve Jessop glaube ich nicht pthread_join(tid, &status); ist korrekt, da der zweite Parameter von pthread_join sollte ein Doppelzeiger sein, da int pthread_join(pthread_t tid, void **thread_return);

    – Amjad

    15. Oktober 2020 um 1:41 Uhr

  • @Amjoad: status Typ hat void*Also &status Typ hat void** nach Bedarf.

    – Steve Jessop

    25. Januar 2021 um 18:14 Uhr


Benutzeravatar von Messa
Messa

Ich denke, Sie müssen die Nummer auf dem Heap speichern. Das int ret Die Variable befand sich auf dem Stack und wurde am Ende der Ausführung der Funktion zerstört myThread.

void *myThread()
{
   int *ret = malloc(sizeof(int));
   if (ret == NULL) {
       // ...
   }
   *ret = 42;
   pthread_exit(ret);
}

Vergiss es nicht free es, wenn Sie es nicht brauchen

Eine andere Lösung besteht darin, die Zahl als Wert des Zeigers zurückzugeben, wie Neil Butterworth vorschlägt.

Abhisheks Benutzeravatar
Abhishek

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

void* myprint(void *x)
{
    int k = *((int *)x);
    printf("\n Thread created.. value of k [%d]\n", k);
    //k =11;
    pthread_exit((void *)k);
}

int main()
{
    pthread_t th1;
    int x =5;
    int *y;
    pthread_create(&th1, NULL, myprint, (void*)&x);
    pthread_join(th1, (void*)&y);
    printf("\n Exit value is [%d]\n", y);
}  

  • Rückgabewert einer lokalen Variablen aus der Thread-Funktion. ohne globale Variable zu verwenden.

    – Abhishek

    18. November 2014 um 8:14 Uhr


Benutzeravatar von Maurits Rijk
Maurits Rijk

Sie geben einen Verweis auf zurück ret das ist eine Variable auf dem Stack.

  • Rückgabewert einer lokalen Variablen aus der Thread-Funktion. ohne globale Variable zu verwenden.

    – Abhishek

    18. November 2014 um 8:14 Uhr


Benutzeravatar von Jay
Jay

Frage : Was ist die beste Vorgehensweise zum Zurückgeben/Speichern von Variablen mehrerer Threads? Eine globale Hash-Tabelle?

Dies hängt ganz davon ab, was Sie zurückgeben möchten und wie Sie es verwenden würden. Wenn Sie nur den Status des Threads zurückgeben möchten (sagen Sie, ob der Thread abgeschlossen hat, was er tun wollte), verwenden Sie einfach pthread_exit oder verwenden Sie eine return-Anweisung, um den Wert von der Thread-Funktion zurückzugeben.

Wenn Sie jedoch weitere Informationen wünschen, die für die weitere Verarbeitung verwendet werden, können Sie die globale Datenstruktur verwenden. In diesem Fall müssen Sie jedoch Parallelitätsprobleme behandeln, indem Sie geeignete Synchronisierungsprimitive verwenden. Oder Sie können etwas dynamischen Speicher zuweisen (vorzugsweise für die Struktur, in der Sie die Daten speichern möchten) und ihn über pthread_exit senden, und sobald der Thread beitritt, aktualisieren Sie ihn in einer anderen globalen Struktur. Auf diese Weise aktualisiert nur der eine Hauptthread die globale Struktur, und Parallelitätsprobleme werden gelöst. Sie müssen jedoch sicherstellen, dass der gesamte von verschiedenen Threads zugewiesene Speicher freigegeben wird.

1416140cookie-checkWie gebe ich einen Wert von pthread-Threads in C zurück?

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

Privacy policy