9 Stimmen

Wie man einen pthread stoppt und fortsetzt?

Ich programmiere in C (eigentlich in OOC, das dann zu C kompiliert wird).

Wie kann ich einem Thread beibringen, an einem bestimmten Kontrollpunkt zu warten, bis ein anderer Thread ihm sagt, dass er fortsetzen soll?

Derzeit benutze ich eine Schleife im Thread und überwache eine Variable, die ich aus dem Hauptthread ändere. Aber ich glaube, dass das nicht sehr effizient ist, oder? Außerdem, wenn ich eine Schleife im Thread benutze, sollte ich dann ein sleep in die Schleife einbauen, um nicht die gesamte CPU-Leistung zu verbrauchen?

12voto

Arnaud Le Blanc Punkte 95132

Es scheint, dass du nach pthread_cond_wait und den dazugehörigen Funktionen suchst.

Hier ist ein Zitat aus der manpage mit einem Beispiel:

Betrachte zwei gemeinsam genutzte Variablen x und y, geschützt durch das Mutex mut, und eine Zustandsvariable cond, die signalisiert werden soll, wann immer x größer als y wird.

          int x,y;
          pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
          pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

Das Warten auf x, bis es größer als y ist, erfolgt wie folgt:

          pthread_mutex_lock(&mut);
          while (x <= y) {
                  pthread_cond_wait(&cond, &mut);
          }
          /* auf x und y arbeiten */
          pthread_mutex_unlock(&mut);

Modifikationen an x und y, die dazu führen können, dass x größer als y wird, sollten bei Bedarf das Zustandsignal senden:

          pthread_mutex_lock(&mut);
          /* x und y modifizieren */
          if (x > y) pthread_cond_broadcast(&cond);
          pthread_mutex_unlock(&mut);

Am Ende macht es genau das, was du verlangst: der Thread, der pthread_cond_wait(&cond) aufruft, wird blockiert, bis ein anderer Thread (zum Beispiel dein Hauptthread) pthread_cond_broadcast(&cond) aufruft. Während dieser Zeit befindet sich der Thread im blockierten Zustand und verbraucht keine CPU-Zyklen.

2voto

vmpstr Punkte 4941

Ich denke, das ist ein guter Kandidat für eine Bedingung. Der Thread sollte auf eine Bedingung warten und der andere Thread sollte die Bedingung signalisieren, um diesen Thread fortsetzen zu lassen.

Sie können pthread_cond_init nachschlagen und das sollte zu anderen Funktionen führen.

2voto

pmdj Punkte 19560

Sie sollten sich näher mit geeigneten Synchronisierungsprimitiven wie Mutexen, Bedingungsvariablen und Semaphoren befassen. In diesem Fall scheint es, dass eine Bedingungsvariable das geeignetste Werkzeug aus der pthreads-Bibliothek ist.

1voto

johnnycrash Punkte 4924

Nur damit Sie wissen, was los war, verbraucht eine "strenge Schleife" Ihre Thread-CPU-Zuweisung genauso wie jeder andere Code, den Ihr Thread ausführt. Der einzige Unterschied besteht darin, dass sie nichts erreicht. Nun ja, ich nehme an, den Kern warm zu machen, ist etwas... Sie möchten das wahrscheinlich nie tun, es sei denn, Sie kümmern sich um die Kosten des Kontextwechsels und Sie wissen sicher, dass die Wartezeit viel kürzer sein wird als die Zeitscheibe Ihres Threads, die etwa 1 ms beträgt. Ich weiß nicht, ob Sleep genauso schlimm ist wie Yield (soweit ich weiß, setzt Yield Ihren Thread ans Ende der Liste der Threads, die auf Ihrer Prioritätsebene aktiviert werden), aber beide verursachen zumindest die Strafe eines Kontextwechsels. Es gibt Kosten für den Kontextwechsel. Ein Kontextwechsel tritt ein, wenn die Zeitscheibe Ihres Threads endet. Dies kann entweder geschehen, weil Sie sie mit einem Yield oder einem Sleep beendet haben oder wenn der Kernel Sie präemptiert hat. Lesen Sie über SMP und Spinlocks, um mehr über Kontextwechsel und Fälle zu erfahren, in denen eine strenge Schleife anwendbar ist.

Außerdem, wenn Sie schlafen, wissen Sie nicht genau, wann Sie wieder aufwachen. Ein Grund, warum Sie vielleicht nicht schlafen möchten, ist, dass Sie etwas schnell erledigen müssen. Sie könnten ein paar ms warten, bevor Sie neu geplant werden.

Jeder andere hat Ihnen die Lösung mit pthread_cond_wait gegeben, die eine Sperre über Mutexe erfordert und einfach und unkompliziert aussieht. Die Leistung könnte für Ihre Bedürfnisse ausreichend sein, ist jedoch im Vergleich zu einem Lösungsansatz mit Signalen relativ langsam (sigwait und pthread_kill). Die Komplexität kommt langsam auf Sie zu.

Hier wird nicht diskutiert, warum Sie ein Mutex sperren, bevor Sie testen, ob Sie auf die Bedingung warten müssen. Der Grund ist, dass Code wie dieser einen Fehler hat:

      while (x <= y) {
              pthread_cond_wait(&cond, &mut);
      }

Ihr Thread könnte prüfen (X<=Y), sehen, dass er warten muss, aber vor dem Anhängen an den Bedingungswert preemtiert werden, bevor ein anderer Thread, der gerade x oder y geändert hat, das Signal in diesem Zeitscheibe vor dem Ersten an die Bedingung heftet. Auf diese Weise geht das Bedingungssignal verloren. Daher müssen überall, wo Sie die Variablen ändern, die das Signal beeinflussen, Sperren hinzugefügt werden.

      pthread_mutex_lock(&mut);
      /* X und Y ändern */
      if (x > y) pthread_cond_broadcast(&cond);
      pthread_mutex_unlock(&mut);

Dies bedeutet, dass Sie diese Mutex-Sperren an vielen verschiedenen Stellen hinzufügen und Ihr Code aufgrund dessen komplexer und langsamer wird. Die Möglichkeit eines hängenden Threads, der auf eine Bedingung wartet, besteht immer. Die Schleifen-, Test-, Schlaf-Lösung hat keine dieser Probleme. Wenn die Wartezeit kurz ist, ist die Verwendung von Sleep in einer Schleife wahrscheinlich eine gute Lösung. Insbesondere, wenn Sie zwischen den Tests eine Sekunde oder mehr schlafen können. Wenn Sie dies können, dann kümmern Sie sich nicht um Mutexe und Bedingungen. Wenn die Schlafzeit kurz ist, wie 1 ms, und die Wartezeit lang ist, wie Minuten oder Stunden, werden Sie letztendlich einige Ressourcen verschwenden, indem Sie kontinuierlich aufwachen und wieder einschlafen. Sie müssen abwägen.

Außerdem ist zu beachten, dass der Kernel manchmal versucht, den wartenden Thread sofort zu wecken und manchmal eine Verzögerung auftritt. Wenn der Thread zu früh aufwacht, wird er aufwachen, während das Mutex gesperrt ist, und sofort wieder einschlafen, bis das Mutex entsperrt ist. Wenn das zum Problem wird, signalisieren Sie die Bedingung auf diese Weise:

pthread_mutex_lock(&mut);
/* X und Y ändern */
if (x > y) {
    pthread_mutex_unlock(&mut);
    pthread_cond_broadcast(&cond);
} else
    pthread_mutex_unlock(&mut);

Danke an Benutzer576875, dessen Codebeispiele ich kopiert habe.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X