Wie fragen Sie einen pthread ab, um zu sehen, ob er noch läuft?

Lesezeit: 11 Minuten

In meinem Destruktor möchte ich einen Thread sauber zerstören.

Mein Ziel ist es, auf die Ausführung eines Threads zu warten und DANN den Thread zu zerstören.

Das einzige, was ich über die Abfrage des Status eines pthreads gefunden habe, ist pthread_attr_setdetachstate aber das sagt dir nur, ob dein Thread ist:

  • PTHREAD_CREATE_DETACHED
  • PTHREAD_CREATE_JOINABLE

Beides hat nichts damit zu tun, ob der Thread noch läuft oder nicht.

Wie fragen Sie einen pthread ab, um zu sehen, ob er noch läuft?

  • Siehe auch stackoverflow.com/questions/1693180/…

    – Benutzer470379

    13. Januar 2011 um 21:15 Uhr

  • 10 Jahre alt, aber hier geht es … was meinst du mit “warten, bis ein Thread die Ausführung beendet hat, und dann den Thread zerstören”? Wenn ein Thread die Ausführung beendet, wird er zerstört.

    – Papajony

    12. Mai 2020 um 8:41 Uhr

Es hört sich so an, als hätten Sie hier zwei Fragen:

Wie kann ich warten, bis mein Thread fertig ist?

Antwort: Dies wird direkt von pthreads unterstützt – machen Sie Ihren zu stoppenden Thread JOINABLE (wenn er zum ersten Mal gestartet wird) und verwenden Sie pthread_join(), um Ihren aktuellen Thread zu blockieren, bis der zu stoppende Thread nicht mehr länger ist laufend.


Wie kann ich feststellen, ob mein Thread noch läuft?

Antwort: Sie können ein “thread_complete”-Flag hinzufügen, um den Trick auszuführen:

Szenario: Thread A möchte wissen, ob Thread B noch am Leben ist.

Wenn Thread B erstellt wird, erhält er einen Zeiger auf die “thread_complete”-Flag-Adresse. Das Flag “thread_complete” sollte auf NOT_COMPLETED initialisiert werden, bevor der Thread erstellt wird. Die Einstiegspunktfunktion von Thread B sollte sofort pthread_cleanup_push() aufrufen, um einen “Bereinigungshandler” zu pushen, der das Flag “thread_complete” auf COMPLETED setzt.

Details zu Cleanup-Handlern finden Sie hier: pthread-Bereinigungshandler

Sie sollten einen entsprechenden pthread_cleanup_pop(1)-Aufruf einschließen, um sicherzustellen, dass der Cleanup-Handler in jedem Fall aufgerufen wird (dh ob der Thread normal beendet wird ODER aufgrund eines Abbruchs usw.).

Dann kann Thread A einfach das “thread_complete”-Flag überprüfen, um zu sehen, ob Thread B bereits beendet wurde.

HINWEIS: Ihr „thread_complete“-Flag sollte als „volatile“ deklariert werden und ein atomarer Typ sein – die GNU-Compiler stellen das sig_atomic_t für diesen Zweck bereit. Dadurch können die beiden Threads konsistent auf dieselben Daten zugreifen, ohne dass Synchronisationskonstrukte (Mutexe/Semaphore) erforderlich sind.

  • Die Cleanup-Handler sind völlig unnötig, es sei denn, Sie verwenden Abbruch (was im Allgemeinen ein ziemlich gefährliches Werkzeug ist). Außerdem möchten Sie möglicherweise eine pthread-Bedingungsvariable zusammen mit der Flag-Variable verwenden, um das Warten darauf zu ermöglichen, ohne CPU-Zyklen zu drehen und zu verbrennen.

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

    13. Januar 2011 um 1:09 Uhr

  • Wenn das Ziel darin besteht, zu wissen, ob join aufgerufen werden soll, um ein pthread_t-Handle zu “zerstören”, funktioniert das Überprüfen eines Flags nicht, da der Thread möglicherweise nicht beendet wurde, wenn Sie das Flag überprüfen, aber dennoch beendet wird, bevor er verbunden wird (beachten Sie dass der Beitritt zu einem Thread, der bereits beigetreten ist, zu undefiniertem Verhalten führt und das Verlassen eines Threads, dem beigetreten werden kann, zu einem Leck führt.)

    – Emil

    29. September 2015 um 5:28 Uhr

  • Allen, die die oben genannte Lösung verwenden möchten, habe ich unten mit einem Problem mit dieser Lösung geantwortet. Lesen Sie es, bevor Sie es in Ihrer Lösung anwenden. Es mag in vielen Fällen kein Problem sein, aber Sie möchten vielleicht etwas darüber wissen.

    – neues Haus

    26. September 2016 um 11:25 Uhr

  • @Emil Es gibt kein Problem. Stellen Sie nur sicher, dass Sie Join nur einmal anrufen. Das Rennen ist harmlos – ja, Ihr Join könnte für einen winzigen Bruchteil einer Sekunde blockieren, wenn Sie zufällig das Flag überprüfen, nachdem es gesetzt wurde und bevor der Thread beendet wird, aber der Thread wird sowieso beendet.

    – David Schwartz

    26. September 2016 um 11:30 Uhr

  • In Fällen, in denen Sie etwas berechnen und dann signalisieren thread_completealso kann das Rechenergebnis verwendet werden, das ist falsch. volatile sig_atomic_t kann immer noch neu geordnet werden, sodass es möglicherweise geschrieben wird, bevor das Berechnungsergebnis sichtbar wird und Verbraucher einen ungültigen Zustand sehen können.

    – a3f

    4. Mai 2019 um 15:26 Uhr

Benutzeravatar von pthread_kill
pthread_kill

pthread_kill(tid, 0);

Es wird kein Signal gesendet, aber es wird trotzdem eine Fehlerprüfung durchgeführt, sodass Sie dies verwenden können, um das Vorhandensein von tid zu prüfen.

VORSICHT: Diese Antwort ist falsch. Der Standard verbietet ausdrücklich die Weitergabe der ID eines Threads, dessen Lebensdauer abgelaufen ist. Diese ID kann jetzt einen anderen Thread angeben oder, schlimmer noch, auf freigegebenen Speicher verweisen, was einen Absturz verursacht.

  • Für mein Problem war das genau das, was ich brauchte, um es zu lösen, danke. Ich habe (pthread_kill(tid, 0) != ESRCH) verwendet.

    – leetNachtschatten

    26. Oktober 2012 um 15:21 Uhr

  • Bitte beachten Sie Folgendes: stackoverflow.com/questions/1693180/…

    – Qiu Yangfan

    13. Juni 2015 um 14:12 Uhr

  • @DavidSchwartz In solchen Fällen ist es besser, Ihre Bearbeitung deutlich als etwas zu markieren, das nicht Teil der ursprünglichen Antwort ist, wie hier vorgeschlagen.

    – Teufel

    20. März 2017 um 21:43 Uhr

  • Zusätzlicher Kommentar zur (korrekten) Bearbeitung von David Schwartz – die Manpage (Linux) sagt Folgendes: „POSIX.1-2008 empfiehlt, dass pthread_kill() den Fehler zurückgeben sollte, wenn eine Implementierung die Verwendung einer Thread-ID nach dem Ende ihrer Lebensdauer erkennt ESRCH. Die glibc-Implementierung gibt diesen Fehler in den Fällen zurück, in denen eine ungültige Thread-ID erkannt werden kann. Beachten Sie jedoch auch, dass POSIX sagt, dass ein Versuch, eine Thread-ID zu verwenden, deren Lebensdauer abgelaufen ist, undefiniertes Verhalten erzeugt, und ein Versuch, eine ungültige Thread-ID in einem Aufruf von pthread_kill() zu verwenden, kann beispielsweise einen Segmentierungsfehler verursachen.’

    – Erik Alapää

    27. März 2019 um 8:47 Uhr

Ich denke, alles, was Sie wirklich brauchen, ist pthread_join() aufzurufen. Dieser Aufruf wird erst zurückgegeben, wenn der Thread beendet wurde.

Wenn Sie nur abfragen möchten, ob der Thread noch läuft oder nicht (und beachten Sie, dass dies normalerweise nicht das ist, was Sie tun sollten!), könnten Sie den Thread einen flüchtigen booleschen Wert auf false setzen lassen, kurz bevor er beendet wird. Dann könnte Ihr Haupt-Thread den booleschen Wert lesen und wenn er immer noch wahr ist, wissen Sie, dass der Thread noch läuft. (Wenn es andererseits falsch ist, wissen Sie, dass der Thread zumindest fast weg ist; es kann jedoch sein, dass es immer noch Bereinigungscode ausführt, der auftritt, nachdem es den booleschen Wert auf falsch gesetzt hat, also sollten Sie auch in diesem Fall noch pthread_join vorher aufrufen versuchen, alle Ressourcen freizugeben, auf die der Thread möglicherweise Zugriff hat)

  • +1 für die Erläuterung der potenziellen Rennbedingung und eine einfache Lösung dafür.

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

    13. Januar 2011 um 1:10 Uhr

  • “Dann könnte Ihr Haupt-Thread den booleschen Wert lesen und wenn er immer noch wahr ist, wissen Sie, dass der Thread noch läuft.” — In diesem Fall würden Sie nur wissen, ob der Thread sauber beendet wurde oder nicht, was nicht dasselbe ist wie noch läuft oder nicht.

    – Benutzer470379

    13. Januar 2011 um 21:14 Uhr

  • Hmm, ich vermisse hier wahrscheinlich eine Möglichkeit, aber AFAICT, der Thread läuft entweder noch, oder er wurde beendet, oder er ist abgestürzt. Und wenn der Thread abgestürzt ist, hat er den Rest des Prozesses mitgenommen, also gibt es sowieso keinen zweiten Thread mehr, der das erkennt.

    – Jeremy Friesner

    3. Februar 2013 um 4:30 Uhr

Es gibt keine vollständig portable Lösung, prüfen Sie, ob Ihre Plattform pthread_tryjoin_np oder pthread_timedjoin_np unterstützt. Sie prüfen also einfach, ob Thread beigetreten werden kann (natürlich mit PTHREAD_CREATE_JOINABLE erstellt).

Lassen Sie mich auf die “gewinnende” Antwort hinweisen, die einen großen versteckten Fehler aufweist und in einigen Zusammenhängen zu Abstürzen führen kann. Wenn Sie nicht pthread_join verwenden, wird es immer wieder auftauchen. Angenommen, Sie haben einen Prozess und eine gemeinsam genutzte Bibliothek. Rufen Sie die Bibliothek lib.so auf.

  1. Wenn Sie es öffnen, beginnen Sie einen Thread darin. Angenommen, Sie möchten nicht, dass es mit ihm verbunden wird, also legen Sie fest, dass es abnehmbar ist.
  2. Die Logik von Process und Shared Lib erledigt ihre Arbeit usw.
  3. Sie wollen lib.so ausladen, weil Sie es nicht mehr brauchen.
  4. Sie rufen den Thread zum Herunterfahren auf und sagen, dass Sie danach ein Flag aus dem Thread Ihrer lib.so lesen möchten, dass er beendet ist.
  5. Sie fahren mit dlclose in einem anderen Thread fort, weil Sie sehen, dass Sie gesehen haben, dass die Flagge den Thread jetzt als “beendet” anzeigt
  6. dlclose lädt den gesamten Stack- und Code-bezogenen Speicher.
  7. Hoppla, aber dlclose stoppt Threads nicht. Und wissen Sie, selbst wenn Sie sich in der letzten Zeile des Cleanup-Handlers befinden, um die flüchtige atomare Flag-Variable “Thread ist beendet” zu setzen, müssen Sie immer noch von vielen Methoden auf dem Stack zurückkehren, Werte zurückgeben usw. Wenn Dem Thread von #5+#6 wurde eine große Thread-Priorität gegeben, Sie werden dlclose erhalten, bevor Sie den Thread WIRKLICH beenden konnten. Sie werden manchmal einige schöne Abstürze haben.

Lassen Sie mich darauf hinweisen, dass dies kein hypothetisches Problem ist, ich hatte das gleiche Problem bei unserem Projekt.

Benutzeravatar von Eric Buell
Eric Buell

Ich glaube, ich habe eine Lösung gefunden, die zumindest für Linux funktioniert. Immer wenn ich einen Thread erstelle, speichere ich seine LWP (Light Weight Process ID) und weise ihm einen eindeutigen Namen zu, z. int lwp = syscall(SYS_gettid); prctl(PR_SET_NAME, (lang)”eindeutiger Name”, 0, 0, 0);

Dann, um später zu prüfen, ob der Thread existiert, öffne ich /proc/PID/Aufgabe/lwp/comm und lies es. Wenn die Datei existiert und ihr Inhalt mit dem eindeutigen Namen übereinstimmt, den ich zugewiesen habe, existiert der Thread. Beachten Sie, dass dies KEINE möglicherweise nicht mehr funktionierende/wiederverwendete TID an eine Bibliotheksfunktion weitergibt, also keine Abstürze.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <sys/file.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <syscall.h>

pthread_t subthread_tid;
int       subthread_lwp;

#define UNIQUE_NAME "unique name"

bool thread_exists (pthread_t thread_id)
{
    char path[100];
    char thread_name[16];
    FILE *fp;
    bool  thread_exists = false;

    // If the /proc/<pid>/task/<lwp>/comm file exists and it's contents match the "unique name" the
    // thread exists, and it's the original thread (TID has NOT been reused).

    sprintf(path, "/proc/%d/task/%d/comm", getpid(), subthread_lwp);

    fp = fopen(path, "r");

    if( fp != NULL ) {

        fgets(thread_name, 16, fp);
        fclose(fp);

        // Need to trim off the newline
        thread_name[strlen(thread_name)-1] = '\0';

        if( strcmp(UNIQUE_NAME, thread_name) == 0 ) {
            thread_exists = true;
        }
    }

    if( thread_exists ) {
        printf("thread exists\n");
    } else {
        printf("thread does NOT exist\n");
    }

    return thread_exists;
}


void *subthread (void *unused)
{
    subthread_lwp = syscall(SYS_gettid);
    prctl(PR_SET_NAME, (long)UNIQUE_NAME, 0, 0, 0);

    sleep(10000);

    return NULL;
}


int main (int argc, char *argv[], char *envp[])
{
    int error_number;

    pthread_create(&subthread_tid, NULL, subthread, NULL);
    printf("pthread_create()\n");
    sleep(1);
    thread_exists(subthread_tid);

    pthread_cancel(subthread_tid);
    printf("pthread_cancel()\n");
    sleep(1);
    thread_exists(subthread_tid);

    error_number = pthread_join(subthread_tid, NULL);
    if( error_number == 0 ) {
        printf("pthread_join() successful\n");
    } else {
        printf("pthread_join() failed, %d\n", error_number);
    }
    thread_exists(subthread_tid);

    exit(0);
}

Benutzeravatar von Priyesh Shah Pilu
Priyesh Shah Pilu

#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>

void* thread1 (void* arg);
void* thread2 (void* arg);

int main()
{
    pthread_t thr_id;

    pthread_create(&thr_id, NULL, thread1, NULL);

    sleep(10);
}

void* thread1 (void* arg)
{
    pthread_t thr_id = 0;

    pthread_create(&thr_id, NULL, thread2, NULL);

    sleep(5);
    int ret = 0;
    if( (ret = pthread_kill(thr_id, 0)) == 0)
    {
        printf("still running\n");
        pthread_join(thr_id, NULL);
    }
    else
    {
        printf("RIP Thread = %d\n",ret);
    }
}

void* thread2 (void* arg)
{
//  sleep(5);
    printf("I am done\n");
}

  • Während dieser Code die Frage beantworten kann, verbessert die Bereitstellung von zusätzlichem Kontext dazu, warum und/oder wie dieser Code die Frage beantwortet, seinen langfristigen Wert.

    – JAL

    23. Oktober 2015 um 23:51 Uhr

  • Es ist Ihnen vielleicht nicht bewusst, aber ein pthread_kill für einen toten Thread könnte möglicherweise Ihre Anwendung zum Absturz bringen oder zu unerwarteten Ergebnissen führen, wie z. B. das Freigeben von Speicher, der für etwas anderes verwendet wird. stackoverflow.com/a/1693235/105539

    – Wolomike

    1. April 2016 um 7:32 Uhr

1413320cookie-checkWie fragen Sie einen pthread ab, um zu sehen, ob er noch läuft?

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

Privacy policy