Wie kann ich einen pthread, der sich in einer Endlosschleife befindet, von außerhalb dieser Schleife beenden?

Lesezeit: 5 Minuten

Ich erstelle einen Thread und versetze ihn in eine Endlosschleife. Ich bekomme Speicherlecks, wenn ich den Code mit überprüfe Valgrind. Hier ist mein Code:

#include <pthread.h>
#include <time.h>

void thread_do(void){
    while(1){}
}

int main(){
    pthread_t th;   
    pthread_create(&th, NULL, (void *)thread_do, NULL);

    sleep(2);
    /* I want to kill thread here */
    sleep(2);
    return 0;
}

Also wird ein Thread in main erstellt und führt die ganze Zeit nur thread_do() aus. Gibt es eine Möglichkeit, es von innen zu töten? hauptsächlich nach 2 Sekunden? Ich habe beides ausprobiert pthread_detach(th) und pthread_cancel(th) aber ich bekomme immer noch Lecks.

  • Das Abbrechen von pthreads bedeutet, dass der Thread keine Chance hat, den ihm zugewiesenen Speicher zu bereinigen.

    – Lily Ballard

    31. Oktober 2011 um 23:44 Uhr

  • Ok, ich habe das gelöst, indem ich einfach ein globales habe keepalive=1. Dann habe ich die geändert while(1) zu while(keepalive). Um den Thread jetzt zu beenden, muss ich nur den Wert der Variable keepalive auf 0 ändern und voila!

    – Pithikos

    3. November 2011 um 14:08 Uhr


Benutzer-Avatar
Dimitri

Wie @sarnold betonte, kann Ihr Thread standardmäßig nicht mit abgebrochen werden pthread_cancel() ohne Aufruf von Funktionen, die Abbruchpunkte sind … aber dies kann mit geändert werden pthread_setcanceltype() um den Abbruchtyp des Threads auf asynchron statt auf verzögert festzulegen. Dazu fügen Sie etwas hinzu wie pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); am Anfang Ihrer Thread-Funktion, bevor Sie die Schleife starten. Sie könnten dann den Thread durch einen Aufruf beenden pthread_cancel(th) aus main().

Beachten Sie jedoch, dass das Abbrechen von Threads auf diese Weise (ob asynchron oder nicht) keine in der Thread-Funktion zugewiesenen Ressourcen bereinigt (wie von Kevin in einem Kommentar angemerkt). Um dies sauber zu tun, können Sie:

  • Stellen Sie sicher, dass der Thread nichts tut, was er vor dem Beenden aufräumen muss (zB using malloc() um einen Puffer zuzuweisen)
  • Stellen Sie sicher, dass Sie eine Möglichkeit haben, nach dem Thread an anderer Stelle aufzuräumen, nachdem der Thread beendet wurde
  • Verwenden pthread_cleanup_push() und pthread_cleanup_pop() um Bereinigungshandler hinzuzufügen, um Ressourcen zu bereinigen, wenn der Thread abgebrochen wird. Beachten Sie, dass dies immer noch riskant ist, wenn der Abbruchtyp asynchron ist, da der Thread zwischen dem Zuweisen einer Ressource und dem Hinzufügen des Bereinigungshandlers abgebrochen werden könnte.
  • Vermeide das Benutzen pthread_cancel() und lassen Sie den Thread eine Bedingung prüfen, um zu bestimmen, wann er beendet werden soll (was in lang andauernden Schleifen geprüft würde). Da Ihr Thread dann selbst auf Terminierung prüft, kann er nach der Prüfung alle erforderlichen Aufräumarbeiten durchführen.

Eine Möglichkeit, die letzte Option zu implementieren, besteht darin, einen Mutex als Flag zu verwenden und damit zu testen pthread_mutex_trylock() in eine Funktion verpackt, die in den Schleifentests verwendet werden soll:

#include <pthread.h>
#include <unistd.h>
#include <errno.h>

/* Returns 1 (true) if the mutex is unlocked, which is the
 * thread's signal to terminate. 
 */
int needQuit(pthread_mutex_t *mtx)
{
  switch(pthread_mutex_trylock(mtx)) {
    case 0: /* if we got the lock, unlock and return 1 (true) */
      pthread_mutex_unlock(mtx);
      return 1;
    case EBUSY: /* return 0 (false) if the mutex was locked */
      return 0;
  }
  return 1;
}

/* Thread function, containing a loop that's infinite except that it checks for
 * termination with needQuit() 
 */
void *thread_do(void *arg)
{
  pthread_mutex_t *mx = arg;
  while( !needQuit(mx) ) {}
  return NULL;
}

int main(int argc, char *argv[])
{
  pthread_t th;
  pthread_mutex_t mxq; /* mutex used as quit flag */

  /* init and lock the mutex before creating the thread.  As long as the
     mutex stays locked, the thread should keep running.  A pointer to the
     mutex is passed as the argument to the thread function. */
  pthread_mutex_init(&mxq,NULL);
  pthread_mutex_lock(&mxq);
  pthread_create(&th,NULL,thread_do,&mxq);

  sleep(2);

  /* unlock mxq to tell the thread to terminate, then join the thread */
  pthread_mutex_unlock(&mxq); 
  pthread_join(th,NULL);

  sleep(2);
  return 0;
}

Wenn der Thread nicht getrennt ist (das ist im Allgemeinen nicht standardmäßig der Fall), sollten Sie anrufen pthread_join() nach Beendigung des Threads. Wenn der Thread getrennt ist, müssen Sie ihm nicht beitreten, aber Sie wissen nicht genau, wann er endet (oder sogar ungefähr, es sei denn, Sie fügen eine andere Möglichkeit hinzu, um seinen Ausgang anzuzeigen).

  • Um diese Mutex-Lösung für mehrere Pthreads zu verwenden, bräuchte ich einen Mutex pro Thread, richtig? Würden Sie diese Lösung in diesem Fall empfehlen?

    – Ricardo Crudo

    13. Mai 2016 um 13:04 Uhr


  • @RicardoCrudo Nein, nur ein Mutex … wenn needQuit() sperrt es erfolgreich, es entsperrt es gleich danach … nur main() hält den Mutex über einen längeren Zeitraum. Alle Threads mit needQuit() zu prüfen, ob beendet werden soll, wird beendet, sobald nichts anderes den Mutex gesperrt hat, und sie selbst werden ihn nur für einen (sehr, sehr kurzen) Moment sperren. Einziger needQuit() Der Aufruf ist jeweils erfolgreich, aber jeder Thread erhält nacheinander einen erfolgreichen Aufruf.

    – Dimitri

    13. Mai 2016 um 13:33 Uhr

  • soll die asynchrone Stornierung beim Warten funktionieren? pthread_cond_wait(&c, &mtx); in threadFunc habe ich es ohne Erfolg versucht

    – qrtLs

    25. Juni 2018 um 12:01 Uhr


Benutzer-Avatar
Sarnold

Ein paar kleine Gedanken:

  1. Sie versuchen, Ihren Thread zu stornieren, aber wenn die geltenden Stornierungsrichtlinien eine verzögerte Stornierung vorsehen, ist Ihre thread_do() wird niemals abgebrochen, da es niemals Funktionen aufruft, die Abbruchpunkte sind:
    A thread's cancellation type, determined by
    pthread_setcanceltype(3), may be either asynchronous or
    deferred (the default for new threads).  Asynchronous
    cancelability means that the thread can be canceled at any
    time (usually immediately, but the system does not guarantee
    this).  Deferred cancelability means that cancellation will
    be delayed until the thread next calls a function that is a
    cancellation point.  A list of functions that are or may be
    cancellation points is provided in pthreads(7).
  1. Sie treten dem Thread in Ihrem einfachen Beispielcode nicht bei; Anruf pthread_join(3) vor dem Ende Ihres Programms:
    After a canceled thread has terminated, a join with that
    thread using pthread_join(3) obtains PTHREAD_CANCELED as the
    thread's exit status.  (Joining with a thread is the only way
    to know that cancellation has completed.)

1368350cookie-checkWie kann ich einen pthread, der sich in einer Endlosschleife befindet, von außerhalb dieser Schleife beenden?

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

Privacy policy