it-swarm.com.de

Wie fragt man einen Pthread ab, ob er noch läuft?

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

Mein Ziel ist es zu warten, bis ein Thread die Ausführung abgeschlossen hat und DANN den Thread zerstören.

Das einzige, was ich zum Abfragen des Status eines Pthread gefunden habe, ist pthread_attr_setdetachstate , aber dies sagt Ihnen nur, ob Ihr Thread:

  • PTHREAD_CREATE_DETACHED 
  • PTHREAD_CREATE_JOINABLE

Beide haben nichts damit zu tun, ob der Thread noch läuft oder nicht.

Wie fragt man einen Pthread ab, ob er noch läuft?

44

Es klingt, 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 stopenden Thread zu JOINABLE (beim ersten Start) und verwenden Sie pthread_join (), um Ihren aktuellen Thread zu blockieren, bis der zu stopende Thread nicht länger ist Laufen.


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

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

Szenario: Thread A möchte wissen, ob Thread B noch lebt.

Wenn Thread B erstellt wird, erhält er einen Zeiger auf die Flagadresse "thread_complete". Das Flag "thread_complete" sollte vor dem Erstellen des Threads auf NOT_COMPLETED initialisiert werden. Die Einstiegspunktfunktion von Thread B sollte sofort pthread_cleanup_Push () aufrufen, um einen Bereinigungshandler zu drücken, der das Flag "thread_complete" auf COMPLETED setzt.

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

Sie sollten einen entsprechenden pthread_cleanup_pop (1) -Aufruf einschließen, um sicherzustellen, dass der Cleanup-Handler unabhängig von dem was aufgerufen wird (d. H. Wenn der Thread normal beendet wird OR aufgrund eines Abbruchs usw.).

Thread A kann dann einfach das Flag "thread_complete" überprüfen, um zu sehen, ob Thread B bereits beendet wurde.

ANMERKUNG: Ihr Flag "thread_complete" sollte als "flüchtig" deklariert werden und sollte ein atomarer Typ sein - die GNU Compiler stellen den 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.

35
jeremytrimble
pthread_kill(tid, 0);

Es wird kein Signal gesendet, aber es wird immer noch eine Fehlerprüfung durchgeführt, sodass Sie die -Datei auf Vorhandensein von tid prüfen können.

ACHTUNG: Diese Antwort ist falsch. Der Standard verbietet ausdrücklich das Weitergeben der ID eines Threads, dessen Lebensdauer abgelaufen ist. Diese ID kann jetzt einen anderen Thread angeben oder, was noch schlimmer ist, auf freigegebenen Speicher beziehen, der zum Absturz führt.

30
pthread_kill

Ich denke, Sie brauchen wirklich nur pthread_join () aufzurufen. Dieser Aufruf wird nicht zurückgegeben, bis 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önnte der Thread einen flüchtigen booleschen Wert auf false setzen, bevor er beendet wird. Dann könnte Ihr Haupt-Thread den Boolean lesen, und wenn es immer noch wahr ist, wissen Sie, dass der Thread noch läuft. (Wenn dies jedoch falsch ist, wissen Sie, dass der Thread zumindest fast nicht mehr vorhanden ist. Möglicherweise wird jedoch noch Bereinigungscode ausgeführt, der auftritt, nachdem der boolesche Wert auf false gesetzt wurde. Daher sollten Sie auch in diesem Fall noch pthread_join aufrufen versuchen, Ressourcen freizugeben, auf die der Thread möglicherweise Zugriff hat

8
Jeremy Friesner

Es gibt keine vollständig portable Lösung. Prüfen Sie, ob Ihre Plattform pthread_tryjoin_np oder pthread_timedjoin_np unterstützt. Sie müssen also nur prüfen, ob ein Thread hinzugefügt werden kann (natürlich mit PTHREAD_CREATE_JOINABLE erstellt).

5
Dewfy

Ich glaube, ich habe eine Lösung gefunden, die zumindest für Linux funktioniert. Immer wenn ich einen Thread erstelle, muss er seine LWP (Light Weight Process ID) speichern und ihm einen eindeutigen Namen zuweisen, z. B. . int lwp = syscall (SYS_gettid); prctl (PR_SET_NAME, (langer) "eindeutiger Name", 0, 0, 0);

Um zu überprüfen, ob der Thread später existiert, öffne ich/proc /pid/ task /lwp/ comm und lese es. Wenn die Datei existiert und der Inhalt mit dem von mir zugewiesenen eindeutigen Namen übereinstimmt, ist der Thread vorhanden. Beachten Sie, dass dies KEINE möglicherweise nicht mehr benötigten/wiederverwendeten TID an eine Bibliotheksfunktion weitergibt, sodass keine Abstürze auftreten.

#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);
}
0
Eric Buell

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 pthread_join nicht verwenden, wird es immer wieder angezeigt. Angenommen, Sie haben einen Prozess und eine gemeinsam genutzte Bibliothek. Rufen Sie die Bibliothek lib.so auf.

  1. Sie öffnen es, Sie starten einen Thread darin. Nehmen Sie an, Sie möchten nicht, dass es mit dem Programm verbunden wird.
  2. Verarbeiten Sie die Logik von shared lib und erledigen Sie ihre Arbeit usw.
  3. Sie möchten lib.so laden, weil Sie es nicht mehr brauchen.
  4. Sie rufen ein Herunterfahren des Threads auf und sagen, dass Sie anschließend ein Flag aus dem Thread Ihrer lib.so lesen möchten, das damit abgeschlossen ist.
  5. Sie fahren mit dlclose mit einem anderen Thread fort, da Sie sehen, dass das Flag jetzt den Thread als "beendet" anzeigt.
  6. dlclose lädt den gesamten mit dem Stapel und Code zusammenhängenden Speicher aus.
  7. Whops, aber dlclose stoppt keine Threads. Und selbst wenn Sie sich in der letzten Zeile des Cleanup-Handlers befinden, um die flüchtige atomare Flag-Variable "Thread is beendet" festzulegen, müssen Sie immer noch von vielen Methoden auf dem Stack zurückkehren, Werte zurückgeben usw. Dem Thread von # 5 + # 6 wurde eine große Thread-Priorität zugewiesen. Sie erhalten dlclose, bevor Sie den Thread wirklich WIRKLICH anhalten können. Sie werden manchmal ein paar schöne Abstürze haben.

Ich möchte darauf hinweisen, dass dies kein hipothetisches Problem ist. Ich hatte das gleiche Problem mit unserem Projekt.

0
newhouse