Forum: Compiler & IDEs Variable innerhalb eines Threads ändern


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 S. (sany)


Lesenswert?

Hallo,

Habe ein kleines Problem...

Ich habe folgenden Simplen Code:
1
uint8_t refVal = 0;
2
bool isRailConnected = false;
3
4
void i2c_commTask(void *argument)
5
{
6
 for(;;)
7
 {
8
   if(!isRailConnected)
9
   {
10
       isRailConnected = true;
11
       refVal = 1;
12
   }
13
   vTaskDelay(1);
14
 }
15
}

Nun wird zwar bis zum nächsten Durchlauf "isRailConnected" auf true 
gesetzt, aber beim nächsten Durchlauf der for schleife ist 
"isRailConnected" wieder auf false und refVal = 0....

Was muss ich tun, um aus dem gestarteten Thread die Variablen außerhalb 
zu ändern?

Das ganze läuft auf einem STM32F407VET6 und C++....

vielen Dank,
Daniel

: Bearbeitet durch User
von Foobar (asdfasd)


Lesenswert?

Warum sollte refVal wieder 0 werden?  Der gepostete Code ist daran nicht 
Schuld.

Btw, diese Pollerei ist kein guter Stil ... das delay(1) sollte eine 
wait_for_railchange() o.ä. sein.

von Andras H. (kyrk)


Lesenswert?

uint8_t refVal = 0;
bool isRailConnected = false;

uint8 und bool und noch vermutlich verschiedene Contexte. Da würde ich 
aufpassen. Denn STM32 ist ja 32 bit weit. Wenn der Compiler den uint8 
und den bool dann in eine 32 bit RAM unterbringt dann wird nicht immer 
bei read modify write zufriffen richtig funktionieren.

Also bei Verschidene Contexten (main, isr, task) dann gucken das 
Variablen die über contexte hinweg gehen, am besten immer den intrinsic 
bitweite haben. Also hier 32 bit.

Dann sollte man prinzipiell gucken, dass der Compiler am besten hier 
auch nicht optimiert und die uint8 variablen in 4er Pakete 
zusammenpackt.

von Daniel S. (sany)


Lesenswert?

Sonst würde ich nicht fragen :-)
Die Variablen werden einmal in der main.cpp so definiert und durch 
nichts anderes beschrieben.

"isRailConnected" nimmt immer wieder den "default" "false" wert ein, 
obwohl er im Thread auf "true" gesetzt wurde. Beim Debuggen kann ich 
klar sehen, bis zum Ende der for schleife ist die Variable auf "true" 
wie gesetzt.

Beginnt die for(;;) von vorne, ist der Wert plötzlich wieder "false"...

von Daniel A. (daniel-a)


Lesenswert?

In C gibt es _Atomic und funktionen wie atomic_compare_exchange_strong 
in der stdatomic.h. C++ hat std::atomic<T>. Ob die auf deiner Platform 
verfügbar sind, weiss ich aber nicht.

Ich würde sowas zwar auch anders lösen. z.B. eine Task Queue und ein 
Thread Pool mit Workern, die die Tasks abarbeiten wenn sie gebraucht 
werden. Oder jenachdem würde ich Green Threads statt echte, oder eine 
Kombination davon, nehmen.

von Bruno V. (bruno_v)


Lesenswert?

Daniel S. schrieb:
> "isRailConnected" nimmt immer wieder den "default" "false" wert ein,
> obwohl er im Thread auf "true" gesetzt wurde. Beim Debuggen kann ich
> klar sehen, bis zum Ende der for schleife ist die Variable auf "true"
> wie gesetzt.

Dann sind das Artefakte, weil Du mit Optimierung arbeitest und das alles 
wegoptimiert ist.

Printe die Variable z.B. in main aus, und Du wirst sehen, dass sie 1 
wird und bleibt.

von Norbert (der_norbert)


Lesenswert?

Wir haben früher™ gerne einen Pin ein/aus/umgeschaltet und ein Scope 
drangehängt. Dann sieht man in Echtzeit was/wo/wann passiert.

von J. S. (jojos)


Lesenswert?

Die Variable mal volatile deklarieren? Glaube zwar auch nicht das es das 
ist, und wenn es immer noch passiert wird die variable woanders 
überschrieben. Oder die ganze Mühle crashed irgendwo und du hast einen 
Reset dazwischen.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

J. S. schrieb:
> Die Variable mal volatile deklarieren? Glaube zwar auch nicht das es das
> ist, und wenn es immer noch passiert wird die variable woanders
> überschrieben.

Das ist in Multithreading-Systemen nicht ausreichend.

Daniel S. schrieb:
> Die Variablen werden einmal in der main.cpp so definiert und durch
> nichts anderes beschrieben.

Wenn die Variable nur in dem einen thread genutzt wird, muss das so 
funktionieren und du musst keine Vorkehrungen treffen. Da es ja eine 
globale Variable ist, kannst du im Debugger einfach einen Watchpoint 
drauf setzen und dann sehen wo sie wieder modifiziert wird. Vielleicht 
ist es ein wilder Pointer.

von J. S. (jojos)


Lesenswert?

Der gezeigte Code ist ja sicherlich nur ein Ausschnitt. Jede gute IDE 
kann die Referenzen von Variablen/Funktionen anzeigen, wurde darüber 
gesucht wer die Variable beschreibt? Liegen Arrays davor wo ein falscher 
Index eventuell böses treibt? Warnungen für implizite Funktionsaufrufe 
an und überprüft?
Live View für Variable benutzt?

von Til S. (Firma: SEGGER) (til_s)


Lesenswert?

Zeig doch mal das Disassembly der i2c_commTask() bzw. step da im 
Disassembly durch. Dann kann man genau sehen, was passiert.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Vermutlich tritt das Problem nur in einem größeren Kontext auf und nicht 
mit dem Minimalbeispiel. @TO: Ist meine Annahme richtig?

Ich tippe auf einen Bufferoverflow einer Variable, die oberhalb der 
gezeigten Vafiablendefinition ist.

Beispiel:
1
uint8_t buffer[16];
2
uint8_t refVal = 0;
3
bool isRailConnected = false;
4
...
5
buffer[16] = 0; // overwrite refVal

Der Code überschreibt höchstwahrscheinlich refVal mit 0 - kommt auf das 
Alignment an. Eventuell muss man hier den Index noch ein wenig rauf oder 
runterschieben...

: Bearbeitet durch Moderator
von Jim M. (turboj)


Lesenswert?

Daniel S. schrieb:
> Was muss ich tun, um aus dem gestarteten Thread die Variablen außerhalb
> zu ändern?
1
volatile uint8_t refVal = 0;
2
volatile bool isRailConnected = false;

Ansonsten schmeisst der Optimizer den Speicherzugriff zum Lesen raus, da 
sich die Variable im ihm zugänglichen Code Teil nicht geändert hat.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Jim M. schrieb:
> Ansonsten schmeisst der Optimizer den Speicherzugriff zum Lesen raus, da
> sich die Variable im ihm zugänglichen Code Teil nicht geändert hat.

volatile ist kein Allheilmittel. Selbst wenn der Compiler den 
Variablenzugriff optimieren würde, sollte es innerhalb dieses Threads 
trotzdem konsistent funktionieren, was es nicht tut:

Daniel S. schrieb:
> Beginnt die for(;;) von vorne, ist der Wert plötzlich wieder "false"...

Daniel S. schrieb:
> Die Variablen werden einmal in der main.cpp so definiert und durch
> nichts anderes beschrieben.

Die Variable wird höchstwahrscheinlich durch einen wilden Pointer 
überschrieben. Das ist mit einem Watchpoint im Debugger in 3 Minuten 
gefunden.

: Bearbeitet durch User
von 900ss (900ss)


Lesenswert?

Niklas G. schrieb:
> Die Variable wird höchstwahrscheinlich durch einen wilden Pointer
> überschrieben. Das ist mit einem Watchpoint im Debugger in 3 Minuten
> gefunden.

Ein simpler Stacküberlauf könnte auch dazu führen.

Man könnte die Variablen einfach "ganz woanders" anlegen, so daß sie 
woanders im Speicher liegen. Oder davor und danach jeweils ein 
Dummyarray anlegen, damit sich die Variablen im Speicher verschieben.
Wenn sie dann "heile" bleiben, ist es wohl so ein Problem welches jetzt 
natürlich andere Daten überschreibt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.