Forum: PC-Programmierung C unerklärliches Programmverhalten


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Daniel A. (daniel-a)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich wollte unechtes multitasking in c mithilfe eines Timers und einem 
Signalhandler unter Linux Implementieren, um es später auf einen uC mit 
Timerinterrupt zu portieren.

Aber das Programm tut etwas, das da einfach nicht steht:
    if(num_running_threads>=MAX_THREADS)
      goto add_thread_failture_maxthreads_exceeded;
    for(int current_thread=MAX_THREADS;current_thread--;){
      printf("create_thread %d %s\n", current_thread, threads[current_thread].active?"active":"inactive");
      if(!threads[current_thread].active)
        break;
    }
    num_running_threads++;
    printf("create_thread %d %d\n",num_running_threads, current_thread);

Führt irgendwie zur Ausgabe von:
save_current_thread 0
create_thread 7 inactive
create_thread 1 0
save_current_thread 0
continue_current_thread 0
save_current_thread 0
continue_current_thread 0
save_current_thread 0
continue_current_thread 0
save_current_thread 0

Und das verstehe ich nicht, diese Zeile:
create_thread 7 inactive
create_thread 1 0
Sollte so Aussehen:
create_thread 7 inactive
create_thread 1 7

Was könnte hier Passiert sein?

Komplettes Programm ist im Anhang.

Ausfgeführt hab ich das so:
gcc -std=c99 -Wall -Wextra -pedantic isr_timerbased_task_sheduler.c -o isr_timerbased_task_sheduler
./isr_timerbased_task_sheduler>log.txt&sleep 0.1;kill $!;head log.txt;
System:
Linux Server1-hp 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
Compiler:
gcc (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

von Peter II (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
was soll der mist mit den gotos?

von Daniel A. (daniel-a)


Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> was soll der mist mit den gotos?

Ich fand es schöner die Einzelnen Programmteile mit labeln zu 
beschriften, als grosse unübersichtliche verschachtelte if und switch 
strukturen zu verwenden. Die gotos erfüllen ihren zweck.

Ich hab diesen Fehler gerade gefunden:
for(int current_thread=MAX_THREADS;current_thread--;){
Muss natürlich so sein:
for(current_thread=MAX_THREADS;current_thread--;){

Jetzt bekomme ich aber einen SIGSEGV, hoffentlich sind setjmp und 
longjmp überhaupt auf diese weise Anwendbar...

von TriHexagon (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Daniel A. schrieb:
> Peter II schrieb:
>> was soll der mist mit den gotos?
>
> Ich fand es schöner die Einzelnen Programmteile mit labeln zu
> beschriften, als grosse unübersichtliche verschachtelte if und switch
> strukturen zu verwenden. Die gotos erfüllen ihren zweck.

Wenn du den Programmfluss verschleiern willst nur zu.

von radiostar (Gast)


Bewertung
1 lesenswert
nicht lesenswert
TriHexagon schrieb:
> Wenn du den Programmfluss verschleiern willst nur zu.

Wer keine Ahnung vom Programmieren hat, der kann sich mit gotos 
natürlich übel seinen Code verunstalten. Es gibt aber Situationen, in 
dene gotos durchaus übersichtlicher sind, und dann ist es auch sinnvoll, 
diese einzusetzen. Mir ist nicht klar, was das mit verschleiern zu tun 
hat - im Gegenteil.

von Peter II (Gast)


Bewertung
0 lesenswert
nicht lesenswert
radiostar schrieb:
> Es gibt aber Situationen, in
> dene gotos durchaus übersichtlicher sind,

da ist hier aber nicht der Fall. Der code ist damit sehr 
unübersichtlich.

wenn man Funktionen beschreiben will, dann verwenden man 
Prozeduren/Funktionen und nicht Labels.

von c-liker (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Peter II schrieb:
> wenn man Funktionen beschreiben will, dann verwenden man
> Prozeduren/Funktionen und nicht Labels.
und nicht zu vergessen Kommentare.

von TestTriHexagon (Gast)


Bewertung
0 lesenswert
nicht lesenswert
radiostar schrieb:
> TriHexagon schrieb:
>> Wenn du den Programmfluss verschleiern willst nur zu.
>
> Wer keine Ahnung vom Programmieren hat, der kann sich mit gotos
> natürlich übel seinen Code verunstalten. Es gibt aber Situationen, in
> dene gotos durchaus übersichtlicher sind, und dann ist es auch sinnvoll,
> diese einzusetzen. Mir ist nicht klar, was das mit verschleiern zu tun
> hat - im Gegenteil.

Wenn man strukturiert in C programmiert, dann werden die Anweisungen 
standardmäßig von oben nach unten ausgeführt. Ausnahme sind höchstens 
Schleifen und Funktionen/Prozeduren. Bei der richtigen Einrückung hat 
man dann noch quasi visuell den Programmablauf im Auge und kann einzelne 
Abschnitte wie Schleifen einfach überspringen. Bei deinem gotos springst 
du mal nach unten, mal nach oben und man muss ständig nach Labels 
suchen. Das ist wie bei einem Buch in dem man sich ständig Verweise 
anschauen muss, was den Lesefluss absolut abträglich ist.

Es gibt Fälle in dem Gotos angebracht sind, doch hier sehe ich keine.

von Daniel A. (daniel-a)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
c-liker schrieb:
> Peter II schrieb:
>> wenn man Funktionen beschreiben will, dann verwenden man
>> Prozeduren/Funktionen und nicht Labels.
> und nicht zu vergessen Kommentare.

Ok, ich werde mir sowieso einen neuen Ansatz überlegen müssen, und dass 
Programm nochmal neu schreiben.

Es scheint folgendes zu passieren:
 1) main
 2) timer stackframe speichern
 3) funktion threadX aufrufen
 4) timer stackframe speichern
 5) timer stackframe nach main widerherstellen
 6) timer verlassen, zu main zurückkehren
 7) timer stackframe speichern
 8) timer stackframe nach timerX widerherstellen
    -> Zerstört stäck weil:
      * main
      * 1. stackframe timer <-- ist bereits zurückgekehrt, alles 
folgende existiert nichtmehr auf dem stack
      * timerX
      * 2. stackframe <-- widerherstellung zerstört den stack

Passt auch zur ausgabe von valgrind (im Anhang)

von Daniel A. (daniel-a)


Bewertung
0 lesenswert
nicht lesenswert
TestTriHexagon schrieb:
> Bei deinem gotos springst
> du mal nach unten, mal nach oben

Dan hast du meinen Code nicht sehr genau Angeschaut, Da springe ich 
immer von oben nach unten, aber nie von unten nach oben.

von TriHexagon (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Daniel A. schrieb:
> TestTriHexagon schrieb:
>> Bei deinem gotos springst
>> du mal nach unten, mal nach oben
>
> Dan hast du meinen Code nicht sehr genau Angeschaut, Da springe ich
> immer von oben nach unten, aber nie von unten nach oben.

Mhm hab noch mal drüber geschaut, hätte schwören können das es einen 
Sprung nach oben gab. Na egal.

Wie Peter schon anmerkte sind Funktionen anstatt der Labels besser 
geeignet. Aber das musst du wissen.

von Bastler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Longjmp restauriert doch auch den Stack-Pointer. Hab ich was übersehen, 
oder wo werden die n Stacks verwaltet?

von Daniel A. (daniel-a)


Bewertung
0 lesenswert
nicht lesenswert
Bastler schrieb:
> Longjmp restauriert doch auch den Stack-Pointer. Hab ich was übersehen,
> oder wo werden die n Stacks verwaltet?

Nein, da hast du recht, deshalb zerstört der longjump ja den stack: die 
stackframes sind zu dem zeitpunkt nichtmehr da, darum ist der 
Stackpointer danach ja auch irgendwo im nirvana und der stack zerstört.

von Bastler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Für preemptive braucht man je Task einen eigenen Stack. Und etwas ASM um 
ein setjump/longjump mit Stack-Umschaltung auf der jeweiligen Plattform 
zu implementieren. Und unter Linux könnte es sein, daß der Stack nicht 
beliebig auf dem Heap liegen darf, aber dazu könnte man die Task-Stacks 
als lokale Variablen in main() definieren. Ob man dabei was lernt, das 
auf dem μC weiterhilft? Who knows?

von Oliver S. (oliverso)


Bewertung
2 lesenswert
nicht lesenswert
Um mal aufs ursprüngliche Problem zurückzukommen: Zähl mal nach, wie 
viele Variablen namens current_thread es in deinem Programm gibt...

Oliver

von Daniel A. (daniel-a)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> Um mal aufs ursprüngliche Problem zurückzukommen: Zähl mal nach, wie
> viele Variablen namens current_thread es in deinem Programm gibt...

Die überzälige lokale variable habe ich bereits bemerkt:

Daniel A. schrieb:
> Ich hab diesen Fehler gerade gefunden:
for(int current_thread=MAX_THREADS;current_thread--;){
> Muss natürlich so sein:
for(current_thread=MAX_THREADS;current_thread--;){

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.