C++ C++ Threads triggern

T_55

Lieutenant
Registriert
Feb. 2013
Beiträge
638
Hallo,

ist es möglich, dass ein (Haupt)Thread regelmäßig in einem weiteren Ziel-Thread (oder mehreren) eine Ziel-Funktion auslöst während der Ziel-Thread und dessen Variablen am leben bleiben?

Zusammengefasst wäre das Ziel:
- Ziel-Threads und dessen Variablen/Speicher bleiben dauerhaft am leben.
- Ziel-Threads enthalten oder stellen eine Funktion da, welche durch den Haupt-Thread getriggert wird.
- Haupt-Thread triggert völlig unregelmäßig die Funktion in einem oder mehreren Ziel-Threads.
- Haupt-Thread übergibt jedem Thread den er triggert ein paar wenige Werte mit.

Klassischerweise kenne und starte ich einen Thread wie eine Funktion und wenn diese Funktion durchgelaufen ist, stirbt auch der Thread.
Etwa in dem Style:

Code:
void funktion()
{
   // inhalt
}
std::thread(funktion).detach();

Auf dieser Basis fällt mir nur eine Endlosschleife ein, die in den Thread kommt und jeder Durchlauf stellt die zu triggernde Ziel-Funktion dar... aber man bräuchte dann noch etwas, dass wie "blockierendes Warten" funktioniert und auf das Signal des Hauptthreads wartet. Wie das gezielte Triggern zwischen Threads funktioniert weiß ich nicht.

Das blockierendes Warten kenne ich nur von Netzwerksachen aber nicht für Threads. Aber im Prinzip sollten GUIs auch nicht viel anders funktionieren als das was ich vorhabe (event handler oder sowas) daher müsste es doch irgendwas geben.
Vielleicht gibt es auch schickere Lösungen als blockierende Endlosschleifen?

Hat jemand eine Idee wie ich da weiterkomme, was gibt es für Möglichkeiten?

Grüße
 
Welchen Sinn hat es, dass die Hilfsthreads am Leben bleiben und ihren Zustand speichern?

Wenn Du so etwas brauchst, dann erzeuge Dir Hilfsobjekte, die den Zustand bzw. die Daten des gewünschten "Hilfsthreads" enthalten.
Dann rufst Du Deine Hilfsfunktion mit Deinen Parametern und einem Zeiger auf das betreffende Hilfsobjekt auf.
Somit hat der Hilfsthread Zugriff auf seinen virtuellen Zustand.

Der Ansatz nennt sich "Dependency Injection" und führt zu einer Implementierung einer Hilfsklasse, die stateless arbeitet.

Der große Vorteil ist, dass Du Logik entwickeln kannst, die nichts von ihrer Umgebung weiß und somit auch keine Abhängigkeiten von anderen Klassen hat.
Eine derartige Logik kann man isoliert laufen lassen und testen (Stichwort "UnitTest").

Am schönsten ist aber, dass Du keinen Ärger mit der Threadverwaltung und dem Aufräumen derselben hast.

Du musst nur aufpassen, dass Dein Threadaufruf keine RaceConditions hat.
Soll heißen, wenn ein Thread ein Ergebnis in eine variable schreibt, darf kein anderer Thread vorher in dieselbe Variable schreiben.
Falls das doch passieren sollte, gewinnt der Thread, der zuletzt geschrieben hat.
Im schlimmsten Fall schreiben 2 Threads gleichzeitig.
Dann kommt es zu einer Exception.

Um das alles besser zu erklären, müsste man aber genau verstehen, was Du eigentlich vor hast.

PS:

Habe ich erwähnt, dass Multithreading per se erst einmal Leistung frist?
Die Threads müssen schließlich verwaltet werden.
Die Aufgabe eines Threads muss aufwändig genug sein (Zeitbedarf), damit sich der Thread lohnt.
Andernfalls ist single thread schneller.

Bei Endlosschleifen musst Du übrigens aufpassen ein Delay einzubauen.
Sonst erzeugt die Schleife 100% Last in dem Thread bzw. CPU-Kern, auf dem sie läuft.
 
Zuletzt bearbeitet:
Das stimmt schon.

Wie gesagt, man muss verstehen, was genau gemacht werden soll und welche Kriterien im Fokus stehen.

Laufzeiteffizienz ist schön und gut.
Nur jeder versteht etwas anderes darunter.
Man muss es messbar machen, um Unterschiede zur Laufzeit beurteilen zu können.
Den Aufwand scheuen die meisten aber.

Wenn es um professionelle Softwareentwicklung geht, steht meist die Einfachheit (=Wartbarkeit) und die Robustheit des Programms im Vordergrund.
Mitleid mit der Last auf der Maschine ist fehl am Platz.

Schritt zwei ist anschließend zu optimieren, wenn man Schwierigkeiten mit der Performance feststellt.
 
Threadpool nutzen kaeme mir in den Sinn. Oder RunLoop. Vielleicht helfen dir die Stichwoerter ja.
 
Die Threads sollen offen bleiben da sie wie eigene ereignisgesteuerte Programme funktionieren sollen (EDA Event-Driven Architecture).
Es kommen unterschiedliche Sensordaten rein und jede Quelle hat einen eigenen Thread der auf eine Änderung der Werte wartet.
Sobald also ein neuer Wert reinkommt sollen die Quellthreads die entsprechenden Berechnungsthreads triggern.
Wenn die Berechnungsthreads nur eine Quelle verarbeiten würde wäre es einfach, denn dann könnte man die Berechnung einfach in dem Thread machen der die Daten abgreift. ABER es ist so, dass einige Berechnungsthreads von verschiedenen Quellen getriggert werden sollen und dessen Daten verarbeiten. Daher will ich Quellthreads und Verarbeitungsthreads trennen damit wird alles flexibler und die Verarbeitungsthreads können frei wählen von welchen Quellen sie getriggert werden.

Ich könnte auch jede Verarbeitung als eigenen Prozess machen der dann von den Quellen durch TCP/IP im Loopback getriggert wird, allerdings wird dann alles komplizierter da ich die Ergebnisse dann auch wieder zusammenführen will, der Datenaustausch wird einfach nerviger.

Auf den ersten Blick scheint std::condition_variable für die Sache zu passen, damit kann man wohl Threads auf Ereignisse warten lassen und solange blockieren. Ich werde mal gucken was das für ein Overhead erzeugt.

Ein anderer Weg wäre bei jedem Ereignis per std::async die Aufgabe zu verteilen allerdings werden dann teuer permanent neue Threads erzeugt und es müssen dann die kompletten Datenstrukturen der Berechnungsthreads erkennbar global abgelegt werden (zB jeder Verarbeiter bekommt ein Mapeintrag in denen seine Datenstrukturen drin sind) und jeder einzelne Zugriff müsste dann syncronisiert werden was wahrscheinlich sehr viel teurer ist als wenn die Datenstrukturen lokal in einer Threadfunktion gekapselt sind wo sie gebraucht werden.

Insofern schaue ich mir mal std::condition_variable an, damit kann man wahrscheinlich die Variante "blockierende Endlosschleife" gut umsetzen. Das Übergeben der Variablen muss ich dann allerdings noch klären.
 
Zuletzt bearbeitet:
Dass Du für jeden Sensor einen eigenen Thread zum Einlesen der Sensordaten hast, verstehe ich.
Wie zeitkritisch die nachgelagerte Verarbeitung ist, kann ich nicht einschätzen.
Eventuell reicht ein Thread, eventuell brauchst Du so viele, wie Du Quellen hast.
Der Trick ist die Kopplung zwischen den Quell- und den Verarbeitungsthreads.
Ich würde ganz abstrakt eine Kopplung durch Buffer vorschlagen.

Also:

Quelle -- Buffer -- Verarbeitung -- Buffer -- Aufbereitung

In der Objektorientierten Entwicklung wäre das ein producer consumer pattern.
Auf eine threadsichere Implementierung achten!

In .NET ist das alles ganz einfach.
Einfach nach folgenden Klassen googlen:
Task bzw. Threadpool und BlockingCollection

In C++ gibt es bestimmt ähnliches.
 
Zurück
Oben