Wie gebe ich einen Wert von pthread-Threads in C zurück?
Lesezeit: 8 Minuten
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
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
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.
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
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
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.
14161400cookie-checkWie gebe ich einen Wert von pthread-Threads in C zurück?yes
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