Forum: Compiler & IDEs Abfrage auf Null oder "Nicht"!?


von Mure (Gast)


Lesenswert?

Hallo!

Kurze Frage:
Welche Codeausführung ist schneller und warum?
1
unsigned char i;
2
3
...
4
5
void Variante1()
6
{
7
  if(i == 0)
8
   {
9
     i = 1;
10
     /* Code ausführen */
11
     i = 0;
12
   }
13
}
14
15
16
void Variante2()
17
{
18
  if(!i)
19
   {
20
     i = 1;
21
     /* Code ausführen */
22
     i = 0;
23
   }
24
}
25
26
27
void Variante3()
28
{
29
  if(i != 0)
30
   {
31
     i = 1;
32
     /* Code ausführen */
33
     i = 0;
34
   }
35
}
36
37
38
void Variante4()
39
{
40
  if(i > 0)
41
   {
42
     i = 1;
43
     /* Code ausführen */
44
     i = 0;
45
   }
46
}
47
48
49
void Variante5()
50
{
51
  if(i)
52
   {
53
     return;
54
   }
55
56
  i = 1;
57
  /* Code ausführen */
58
  i = 0;
59
}
60
61
void Variante6()
62
{
63
  if(i == 1)
64
   {
65
     return;
66
   }
67
68
  i = 1;
69
  /* Code ausführen */
70
  i = 0;
71
}

Die jeweilige Funktion VarianteX, kann durch Interrupts mehrfach 
aufgerufen werden. Des Wegen die Sperre.

Danke.

Gruß
Mure

von Peter II (Gast)


Lesenswert?

Variante 1 und Variante 2 machen verschiende dinge, da macht ein 
vergleich keinen sinn.

Schau dir doch selber den ASM code an.

von Stefan E. (sternst)


Lesenswert?

Mure schrieb:
> Welche Codeausführung ist schneller und warum?

Wie wäre es mit einfach ausprobieren?
Ich würde allerdings wetten, dass keine Variante irgendwie schneller 
wäre, und die meisten (zumindest 1-4) sogar absolut identischen Code 
erzeugen.

Mure schrieb:
> Die jeweilige Funktion VarianteX, kann durch Interrupts mehrfach
> aufgerufen werden. Des Wegen die Sperre.

Da hilft dir deine Sperre aber nicht wirklich. Was, wenn der Interrupt 
zwischen dem "if" und dem "i = 1;" auftritt?

von Stefan E. (sternst)


Lesenswert?

Peter II schrieb:
> Variante 1 und Variante 2 machen verschiende dinge

Nö. "!i" und "i == 0" sind identisch.

Edit: Allerdings machen Variante 3 und 4 was anderes. Die sollten wohl 
eher nach dem Muster wie 5 und 6 aufgebaut sein.

von Doof (Gast)


Lesenswert?

Mure schrieb:
> Die jeweilige Funktion VarianteX, kann durch Interrupts mehrfach
> aufgerufen werden. Des Wegen die Sperre.

Du hast in diesem Zusammenhang hoffentlich an einen Cache-Flush gedacht, 
oder?

von Mure (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Was, wenn der Interrupt
> zwischen dem "if" und dem "i = 1;" auftritt?

Äh. Gute Frage! - Nächste Frage! Wie löse ich das Problem?

Stefan Ernst schrieb:
> Edit: Allerdings machen Variante 3 und 4 was anderes.

Nochmal Äh! - Richtig erkannt. Falsch von mir getippt!

void Variante3()
{
  if(i != 1)
   {
     i = 1;
     /* Code ausführen */
     i = 0;
   }
}


void Variante4()
{
  if(i > 0)
   {
     return;
   }

  i = 1;
  /* Code ausführen */
  i = 0;
}

Doof schrieb:
> Du hast in diesem Zusammenhang hoffentlich an einen Cache-Flush gedacht,
> oder?

Ein was!? - Nö! Bin wohl doofer als du...

von HildeK (Gast)


Lesenswert?

Stefan Ernst schrieb:
>> Variante 1 und Variante 2 machen verschiende dinge
>
> Nö. "!i" und "i == 0" sind identisch.

Das stimmt schon, aber es trotzdem Varianten dabei, die nicht dasselbe 
tun.

Beispiele:

> void Variante4()
> {
>   if(i > 0)
>    {
>      i = 1;
>      /* Code ausführen */
>      i = 0;
>    }
> }
hier wird bei i>0, also auch bei i==1 der Code ausgeführt,
und

> void Variante6()
> {
>   if(i == 1)
>    {
>      return;
>    }
>
>   i = 1;
>   /* Code ausführen */
>   i = 0;
> }

hier kommt bei i==1 'return' und der Code wird nicht ausgeführt.

von P. M. (o-o)


Lesenswert?

Es dürften alle gleich sein, so lange der Instruktionssatz 
Vergleichsoperationen für Grösser-/Kleiner-/Gleich hat.

Achja: Deine Sperre ist keine gute Implementation für das Problem. 
Einerseits kann, wie bereits gesagt wurde, der Interrupt genau in die 
Änderung von i reinfunken. Klingt unwahscheinlich, wird in der Praxis 
aber sicher passieren und kaum zu findende Fehler auslösen. Andererseits 
weist die Sperre darauf hin, dass deine Interruptroutine lang im 
Verhältnis zum Aufrufinterval ist. Alternativ könntest du auch ein Flag 
setzen, das dann in einer Hauptschleife ausgewertet und abgearbeitet 
wird. Oder zumindest die Sperre sauber implementieren, Stichwort: 
http://de.wikipedia.org/wiki/Semaphor_%28Informatik%29

von Stefan E. (sternst)


Lesenswert?

HildeK schrieb:
> Stefan Ernst schrieb:
>>> Variante 1 und Variante 2 machen verschiende dinge
>>
>> Nö. "!i" und "i == 0" sind identisch.
>
> Das stimmt schon, aber es trotzdem Varianten dabei, die nicht dasselbe
> tun.

Was ich in meinen Post ja auch ergänzt hatte. ;-)

von Mure (Gast)


Lesenswert?

Ja aber eine Semaphore und Mutex macht doch auch nichts anderes, als 
sich ein Flag zu setzten ... Mein Flag ist halt "i = 1".
Ich sehe hier den unterschied nicht.

von Stefan E. (sternst)


Lesenswert?

Mure schrieb:
> Ja aber eine Semaphore und Mutex macht doch auch nichts anderes, als
> sich ein Flag zu setzten ... Mein Flag ist halt "i = 1".
> Ich sehe hier den unterschied nicht.

Der springende Punkt ist, dass das "test-and-set" atomar sein muss.

von Mure (Gast)


Lesenswert?

Hm. Kurz nachgedacht. - Wäre dann:
1
void Variante7()
2
{
3
 i++;
4
 if(i == 1)
5
  {
6
    /* Code ausführen */
7
  }
8
 i--;
9
10
 return;
11
}
besser!?

von Mure (Gast)


Lesenswert?

Dann müsste man noch i als volatile definieren, dass auch bei der 
if-Abfrage diese neu eingelesen werden muss:
1
volatile unsigned char i;
2
void Variante7()
3
{
4
 i++;
5
 if(i == 1)
6
  {
7
    /* Code ausführen */
8
  }
9
 i--;
10
11
 return;
12
}

von HildeK (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Was ich in meinen Post ja auch ergänzt hatte. ;-)

Jaja, nachdem ich meinen geschrieben hatte ... :-)

von Stefan E. (sternst)


Lesenswert?

Mure schrieb:
> besser!?

Nein, weil hier i++ nicht atomar ist.

von Oliver (Gast)


Lesenswert?

Mure schrieb:
> Dann müsste man noch i als volatile definieren

Solange i++ nicht mit einer atomaren Operation errechnet werden kann, 
nutzt volatile überhaupt nichts, denn dann kann da immer noch ein 
Interrupt dazwischenfunken.

Es nutzt nichts, da muust du die Doku zu deinem Compiler und deinem 
Prozessor lesen, und dafür sorgen, daß i++ oder i=1, oder was auch 
immer, nicht unterbrochen werden kann.

Oliver

von Mure (Gast)


Lesenswert?

Oliver schrieb:
> Es nutzt nichts, da muust du die Doku zu deinem Compiler und deinem
> Prozessor lesen, und dafür sorgen, daß i++ oder i=1, oder was auch
> immer, nicht unterbrochen werden kann.

Ich google schon wie blöde. Finde aber für nen MSP430 keinen Code für ne 
Mutex...

von Stefan E. (sternst)


Lesenswert?

HildeK schrieb:
> Stefan Ernst schrieb:
>> Was ich in meinen Post ja auch ergänzt hatte. ;-)
>
> Jaja, nachdem ich meinen geschrieben hatte ... :-)

Nö, denn man kann einen Post nicht mehr editieren, wenn bereits ein 
weiterer in dem Thread ist. Mein Edit war also mindestens 5 Minuten vor 
deinen Post da. ;-)

von P. M. (o-o)


Lesenswert?

Mure schrieb:
> Ich google schon wie blöde. Finde aber für nen MSP430 keinen Code für ne
> Mutex...

Kann man recht einfach auch selber schreiben. Oder mache die Zuweisung 
an i einfach atomar, indem du Interrupts kurz ausschaltest. Das sollte 
auf dem MSP430 wohl ähnlich funktionieren wie auf einem AVR.

von Bronco (Gast)


Lesenswert?

Du bräuchtest eine Konstruktion wie diese
1
void funktion(...)
2
{
3
  Disable_Interrupts();
4
  if (lock == 0)
5
  {
6
    lock = 1;
7
    Enable_Interrupts();
8
    // Dein Code
9
    lock = 0;
10
    return;
11
  }
12
  Enable_Interrupts();
13
  // return
14
}

Setzt voraus, daß die Zuweisung
1
    lock = 0;
atomar abläuft.

von Mure (Gast)


Lesenswert?

P. M. schrieb:
> Kann man recht einfach auch selber schreiben.

Wenn man weiß wie's geht. Assembler kann ich leider nicht ...


P. M. schrieb:
> der mache die Zuweisung
> an i einfach atomar, indem du Interrupts kurz ausschaltest.

Quasi so was:
1
#define EnterMutex(_myMutex)   _DINT(); /* Disable Global interrupt */ \
2
                               _myMutex++; \
3
                               if(_myMutex != 1){ \
4
                                  goto _LeaveMutex; \
5
                               } \
6
                               _EINT(); /* Enable Global interrupt */\
7
8
#define LeaveMutex(_myMutex)   _DINT(); /* Disable Global interrupt */ \
9
                               _myMutex--; \
10
                               _EINT(); /* Enable Global interrupt */\
11
                                                
12
13
unsigned char i;
14
void Variante7()
15
{
16
  EnterMutex(i);
17
  /* Code ausführen */
18
  LeaveMutex(i);
19
20
 return;
21
}

Aber streng genommen müsste ich den Zustand von Global Interrupt Flag 
abfragen, bevor ich es setze. Ich glaube es ist möglich, das die Mutex 
betreten wird (Main-Loop), wenn der globale Interrupt deaktiviert ist.

von Mure (Gast)


Lesenswert?

Bronco schrieb:
> Du bräuchtest eine Konstruktion wie diese ...

Sieht eigentlich wie meine aus.

von Mure (Gast)


Lesenswert?

Mure schrieb:
> Bronco schrieb:
>> Du bräuchtest eine Konstruktion wie diese ...
>
> Sieht eigentlich wie meine aus.

Ah! - Da fehlt das Label!
1
#define LeaveMutex(_myMutex) _LeaveMutex: 
2
                                _DINT(); /* Disable Global interrupt */ \
3
                                _myMutex--; \
4
                                _EINT(); /* Enable Global interrupt */\

von Mure (Gast)


Lesenswert?

Wieso ist es jetzt hier plötzlich so "still"?!?

von Bronco (Gast)


Lesenswert?

Mure schrieb:
> Bronco schrieb:
>> Du bräuchtest eine Konstruktion wie diese ...
> Sieht eigentlich wie meine aus.
Mure schrieb:
> goto _LeaveMutex; \


Nein, in meiner Konstruktion wäre ganz gewiß kein GOTO!

von Kan a. (Firma: Basta) (kanasta)


Lesenswert?

Ich weiß ne Lösung!

Der C-Chef sagt, so geht das:
(i == 0) ? i = 1 : i = 0;

Eine Zeile, ein Befehl, alles atomar.

von Sven P. (Gast)


Lesenswert?

Kan asta schrieb:
> Ich weiß ne Lösung!
>
> Der C-Chef sagt, so geht das:
> (i == 0) ? i = 1 : i = 0;
>
> Eine Zeile, ein Befehl, alles atomar.
Das ist aber gelogen...

von Mure (Gast)


Lesenswert?

Bronco schrieb:
> Nein, in meiner Konstruktion wäre ganz gewiß kein GOTO!

Richtig, aber was ist daran so schlimm?

Sven P. schrieb:
>> Eine Zeile, ein Befehl, alles atomar.
> Das ist aber gelogen...

Det habe ich mich grad auch gefragt.

von Chris (Gast)


Lesenswert?

Mure schrieb:
> Sven P. schrieb:
>>> Eine Zeile, ein Befehl, alles atomar.

Die gilt nur für Basic Interpreter, die arbeiten nähmlich alles Zeile 
für
Zeile ab. Teilweise sogar für Compiler.

von Sven P. (Gast)


Lesenswert?

Ach ja klar, bei der Syntax der vorangegagenen Beispiele habe ich auch 
sofort an Basic gedacht... und zwar an genau eines der zehntausend 
verschiedenen Dialekte, welches zeilenweise tut :-)

von Mure (Gast)


Lesenswert?

Sven P. schrieb:
> bei der Syntax der vorangegagenen Beispiele habe ich auch
> sofort an Basic gedacht

Jetzt mal ohne SCh***. - Gibt es Basic für die 
Mikrocontroller-Porgrammierung?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Mure schrieb:
> Gibt es Basic für die
> Mikrocontroller-Porgrammierung?

Bascom.

von Mure (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Bascom.

http://www.mcselec.com/index.php?option=com_content&task=view&id=14&Itemid=41
Was es nicht alles gibt ....
Aber Bascom scheint es nur für AVR zu geben.

Gruß
Mure

von Mure (Gast)


Lesenswert?

Zurück zum ursprünglichen Problem:
Richtig schlau bin ich jetzt aber noch immer nicht!

Wie macht man jetzt am Besten eine Mutex für den MSP?
Und zwar so, dass ich diese als Funktion oder Makro habe und in beliebig 
vielen Codeabschnitten einsetzen kann?!?

Gruß
Mure

von Bronco (Gast)


Lesenswert?

Mure schrieb:
> Sven P. schrieb:
>>> Eine Zeile, ein Befehl, alles atomar.
>> Das ist aber gelogen...
>
> Det habe ich mich grad auch gefragt.

Hey Mure,

falls Du das wirklich nicht weißt:
Atomar bedeutet, daß es für die CPU ein ununterbrechbarer Vorgang ist.
Das sind z.B. einzelne Maschinen/Assembler-Befehle.
C-Code wird vom C-Compiler in Maschinen-Code umgewandelt.
D.h. ein C-Befehl ergibt oft in mehrere Maschinen-Befehle und ist 
damit nicht atomar!

Bsp:
8-Bit Microcontroller macht
1
uint32_t x:
2
x++;
Das x++ erzeugt in vier Assembler-Befehle, weil die CPU pro Befehl nur 
jeweils 8 der 32Bit berechnen kann.

So ist es ein sehr typischer Fehler, auf Variablen aus dem Interrupt 
heraus zuzugreifen, dabei solche Befehlsblöcke zu unterbrechnen und 
damit den Variableninhalt zu zerstören.

Falls Du IAR verwendest: lies mal "Monitor"-Funktionen in der Doku nach.

von Mure (Gast)


Lesenswert?

Bronco schrieb:
> Atomar bedeutet, daß es für die CPU ein ununterbrechbarer Vorgang ist.

Habe ich inzwischen verstanden. Deswegen wird ja auch der GIE 
deaktiviert.
Aber mit meinem Makro warst du aber nicht zufrieden.

Bronco schrieb:
> Falls Du IAR verwendest

Nein. Habe Code Composer Studio.

von Peter D. (peda)


Lesenswert?

Beim AVR-GCC gibt es eine <atomic.h>, die sollte sich an den MSP 
anpassen lassen.


Peter

von Mark B. (markbrandis)


Lesenswert?


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.