Threading in der Programmiersprache C

Ein neuer Artikel wurde veröffentlicht
  • Moin!


    Ich bastel seit längerem an einem Webradio- ,Radio- und MP3-Player.


    Eines der Ziele ist, die komplette Bedienung über einen Inkrementalgeber (Drehgeber) abzuwickeln. Unter anderem auch die Lautstärkeregelung.

    Bisher habe ich dafür ein eigenständiges Programm genutzt, das ich mit system("/home/pi/webradio/lautstaerke &"); aufgerufen habe.

    Gestern habe ich mir gedacht, probier es doch mal mit Threading.


    Ich habe mir eine Kurze Funktion geschrieben, die alles wesentlich Merkmale der endgültigen Funktion enthält.

    Der Thread wird auch gestartet und beendet, aber während der Laufzeit wird eine Abfrage des Drehgebers nicht ausgeführt.


    Nun habe ich heute mal ein wenig gelesen.

    Ist es richtig, das ein Thread wie ein eigenständiges Programm handelt?


    Soll heißen, alle benötigten Funktionen müssen sich in dem Thread-Code liegen.


    Funktionen die in einem anderen Programmteil liegen können nicht aus dem Threadingteil angesprochen werden.


    Habe ich das so richtig verstanden?

    Wenn ja, dann kann ich ja alles so lassen wie es ist.


    Gruss Bernd

    Ich habe KEINE Ahnung und davon GANZ VIEL!!
    Bei einer Lösung freue ich mich über ein "Like"

  • Servus DG8BR ,


    Ist es richtig, das ein Thread wie ein eigenständiges Programm handelt?

    ja ... das läuft "quasi" eigenständig ab, unabhängig vom Hauptprogramm ...




    Soll heißen, alle benötigten Funktionen müssen sich in dem Thread-Code liegen.


    Funktionen die in einem anderen Programmteil liegen können nicht aus dem Threadingteil angesprochen werden.

    Das verstehe ich jetzt nicht ... Funktionsnamen in C sind in der Regel global und können demzufolge von überall aufgerufen werden.

    Ausnahmen sind Funktionen, die als "static" definiert sind ... die sind nur im entsprechenden Source-Code-Modul sichtbar.


    cu,

    -ds-

  • Hallo,


    Zitat

    Ist es richtig, das ein Thread wie ein eigenständiges Programm handelt?

    Nee, dann müsstest du einen Prozess starten. Ein Thread ist immer dem Prozess (= dem "Programm") zugeordnet, der den Thread startet. Bei Wikipedia ist es in der Einleitung ganz gut erklärt: https://de.wikipedia.org/wiki/Thread_(Informatik)


    Richtig ist, dass der Thread (quasi-) parallel zum Prozess, der den Thread gestartet hat, etwas macht.


    Zitat

    Soll heißen, alle benötigten Funktionen müssen sich in dem Thread-Code liegen.

    Normalerweise führt man _eine_ Funktion in einem Thread aus. Jeder Thread hat eine Aufgabe. Sollte zumindest so sein. Wenn dein Thread Daten senden oder empfangen soll, dann über ein Queue. Darüber können auch Threads kommunizieren.


    Das ganze gilt so für eigentlich alle Programmiersprache, dass ist jetzt wirklich C-spezifisch.


    Warum dein Thread den Drehregler nicht abfragt kann man aktuell - und ohne Code nicht sagen.

    Grundsätzlich ist nebenläufige Programme aber auch nicht unbedingt einfach zu debuggen, gerade dann, wenn mehrere Threads untereinander agieren.


    Gruß, noisefloor

  • Moin meigrafd,


    Mhm, wie erkläre ich das.

    Das Programm bedient ein TFT-Display per SPI, der Player spielt und ich möchte die Lautstärke ändern können.


    Das Programm "Lautstaerke" fragt, während Musik wiedergegeben wird, den Drehgeber ab und ändert den amixer.



    Gruss Bernd

    Ich habe KEINE Ahnung und davon GANZ VIEL!!
    Bei einer Lösung freue ich mich über ein "Like"

  • Moin!


    noisefloor : Danke für den Link und die Erklärungen.


    meigrafd : Dir auch danke für die Erläuterungen.


    Ich habe noch ein wenig gebastelt. Ich habe den Übeltäter auch gefunden.

    Ich hatte , wegen Prozessorlast ein usleep eingebaut. Aber zu groß gewählt.

    Nun wird die Lautstärke verändert.


    das Ganze ist wieder typisch für mich. Wenn ich nicht weiter komme, muss ich mit jemanden über die Sache sprechen. Dabei fällt mir meistens die Lösung ein.


    Danke euch Beiden.


    Gruss Bernd

    Ich habe KEINE Ahnung und davon GANZ VIEL!!
    Bei einer Lösung freue ich mich über ein "Like"

  • So ergeht es mir auch immer :daumendreh2:


    Wenn ich das richtig verstanden habe hast du dein Programm in mehrere Unterprogramme aufgeteilt? Oder was das obige system(); nur ein Versuch? Fall doch nicht solltest du dein Gerüst noch mal überdenken - ein C Programm schreiben um mehrere system(); ausführen ist "broken by design" ;)



    PS: Ich hab vorhin nichts erläutert ;)

  • So ganz richtig hat's noch keiner beschrieben:


    * Der Prozess hat einen eigenen Adressraum und Prozesskontext

    * In einem Single-Threaded Prozess laeuft darin genau ein Thread, der main-Thread

    * Threads koennen weitere Threads starten die im gleichen Prozesskontext laufen


    -> Jeder Thread hat also Zugriff auf ALLES im selben Prozess


    Das ist einerseits praktisch weil die Threads ueber gemeinsame Variablen kommunizieren koennen,

    aber andererseits GEFAEHRLICH weil der Entwickler sich ganz genau ueberlegen muss was fuer

    Race-Conditions auftraten koennen.


    Threads sind einfach zu starten, aber sie kontrolliert zu beenden ist gar nicht so einfach.


    => Threads nur einsetzen wenn sie wirklich noetig sind erspart VIEL Aerger!

  • Moin!


    Ich habe das Programm, mittlerweise, auf 12 Dateien mit der Endung .c gebracht. Ich kenn das so. Wegen Übersichtlichkeit und Wartung.

    Das Ganze linke und übersetze ich mit einem Makefile.


    Bisher hatte ich 2 system-Aufrufe. den mpg123 und die besagte Lautstärke. Aber die ist zumindest Geschichte...


    meigrafd : Danke zurück genommen ,-))

    dreamshader : Dir den Dank den meigrafd bekommen hat. Ich hoffe er ist dir nicht zu abgenutzt?? Wurde ja nun 2mal benutzt.

    Tell : Nochmal genau nachgesehen. Ja, ist richtig. Dir Danke für die Erklärung.


    So, aber nu is genug....


    Gruss Bernd

    Ich habe KEINE Ahnung und davon GANZ VIEL!!
    Bei einer Lösung freue ich mich über ein "Like"

  • Ich habe noch ein wenig gebastelt. Ich habe den Übeltäter auch gefunden.

    Ich hatte , wegen Prozessorlast ein usleep eingebaut. Aber zu groß gewählt.

    Nun wird die Lautstärke verändert.

    Hallo,

    Fragst Du dabei einen GPIO über die /sys Schnittstelle ab?

    Dann kannst du durch inkludieren von poll.h und registrieren des GPIOs relativ einfach die Prozessorlast praktisch auf null bekommen.

    Die poll() funktion dann in den thread gepackt und das OS weckt Deinen Thread auf wenn was an der Flanke des GPIO passiert.


    Nur falls Du noch ein bisschen basteln möchtest ;)

  • Wenn ich nicht weiter komme, muss ich mit jemanden über die Sache sprechen. Dabei fällt mir meistens die Lösung ein

    ist voll normal


    in meiner Industriezeit steckte ich so tief in der Prüfprogrammprogrammierung (wie alle meine Kollegen jeder an seinem Projekt)

    Ich kam an einen Punkt wo ich kein Land mehr sah, mit Kollegen reden hatte keinen Zweck weil die ja in ihren Projekten tieeef drin steckten und keinen Kopf für mein Projekt hatten.


    Unser Gruppenleiter (der sich nur noch fern ab der Technik als Stundenschreiber und Verteiler sah) hatte ein offenes Ohr, er verstand kein Wort von meinem Problem aber als ich mit ihm redete darüber fiels mir wie Schuppen aus den Haaren, Lösung gefunden, man muss nur mal drüber reden.

    lasst die PIs am Leben !
    Energiesparen:
    Das Gehirn kann in Standby gehen. Abschalten spart aber noch mehr Energie, was immer mehr nutzen. Dieter Nuhr

  • Bisher hatte ich 2 system-Aufrufe. den mpg123 und die besagte Lautstärke. Aber die ist zumindest Geschichte...

    Den system(); Aufruf für mpg123 würde ich ebenfalls vermeiden - generell soweit es geht system(); vermeiden, da jeder system(); Aufruf in einer separaten Shell ausgeführt wird.


    Lad dir den Source von mpg123 und verwende die Teile die du brauchst.


    Wenn du denn trotzdem unbedingt externe Programmaufrufe nutzen willst dann nutze lieber popen(); anstatt system();

  • Hallo Meigrafd,


    nö, im Gegenteil:

    Wenn es darum geht, ein Linu-Kommando aufzurufen, dann mit system() oder die Kaskade mit fork(), exec() etc.


    Wenn es darum geht, Ergebnisse von einem Linux-Kommando zum nächsten zu schicken bzw. zum aufrufenden Programm mehr zu liefern als "funktioniert", dann geht das nur mit popen() (was für pipe open steht).


    Intern passiert dagegen das Gleiche. So gleich, dass Deine Erklärung sogar falsch ist.


    Guckst Du:

    Zitat

    popen() gives you control over the process's input or output file streams. system() doesn't. If you don't need to access the process's I/O, you can use system() for simplicity.

    system() is in C89 and C99; popen() is Posix only (though the Windows API also has one).

    Both functions invoke some form of a shell to execute the command (e.g. /bin/sh on Linux, and probably cmd.exe on Windows). If you want to execute an executable file directly and you are on Posix, you can also look at the exec*-family of functions in conjuction with fork() (since exec() replaces the current process.




    Beste Grüße


    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - ser. Devices - kein Support per PM / Konversation

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Ihr belegt euer Missverständnis doch bereits, wie sollte ich das noch steigern? :-/


    Lernt das gelesene richtig zu verstehen und interpretiert da kein Unfug hinzu.



    Summa Summarum sagte ich nur: Wenn er mpg123 unbedingt extern aufrufen will dann solle er lieber popen(); statt system(); verwenden. Wieso liegt IMHO auf der Hand - Unterschied zwischen system(); und popen();. Siehe stackoverflow Thread den Andreas zitierte, aber die 2. Antwort...

  • Hi,

    also meigrafd , das versteh' ich jetzt aber auch nicht ... :conf:


    Der Unterschied zwischen system() und popen() ist imho lediglich, dass bei popen() zusätzlich eine Kommunikation mit dem aufgerufenen Prozess über IPC (in diesem Fall pipe) möglich ist ... abhängig wiederum vom Modus ( lesen/schreiben/beides).

    Einen "echten" Vorteil hat popen() da meines Wissens nicht ...

    Alternatic kannst Du mit exec...() einen Prozess überlagern (da entfällt dann die shell drunter), solltest aber dann vorher einen fork() machen, sonst wird Dein aktueller Prozess überlagert.


    Etwas ratlos,

    -ds-

  • Der Unterschied zwischen system() und popen() ist imho lediglich, dass bei popen() zusätzlich eine Kommunikation mit dem aufgerufenen Prozess über IPC (in diesem Fall pipe) möglich ist

    Und nun denk mal noch weiter... Wenn man ein Programm zum abspielen startet und etwas anderes abspielen will, was macht man dann sinnvollerweise? Ich würde dann nicht den Prozess beenden und neu starten, sondern den Prozess dahingegend beeinflussen. Kann man das mit system(); ? As Far As I Know, nein. Das alleine ist für zumindest mich bereits ein "echter Vorteil gegenüber system();".


    Rät hier jemand lieber system(); anstatt popen(); zu verwenden :?: Wenn nicht weiß ich wirklich nicht worüber wir uns hier überhaupt unterhalten...