Laden...

[erledigt] Wann wird die per ref übergebene Variable geändert?

Erstellt von esparki vor 9 Jahren Letzter Beitrag vor 9 Jahren 3.008 Views
E
esparki Themenstarter:in
27 Beiträge seit 2006
vor 9 Jahren
[erledigt] Wann wird die per ref übergebene Variable geändert?

Hallo Leute,

ich arbeite gerade an einer SPS-Steuerung. Der gesamte Ablauf wird in C-Sharp programmiert. Die Kommunikation mit der SPS ist über eine eigene Bibliothek realisiert.
Der Ablauf ist folgendermaßen:
Alle 15ms werden nacheinander die folgenden Methoden aufgerufen:

  • lese SPS-Eingänge
  • Werte den Zustand aus und mache etwas (Bearbeite)
  • schreibe SPS-Ausgänge

Die SPS-Ein-und Ausgänge sind jeweils in einer Struktur hinterlegt.
Bisher wurde die Methode "Bearbeite" mit einer switch/case-Anweisung realisiert und nach einem "case-Block" wurde die "switch-Variable" verändert. Beim nächsten Durchgang (nach 15ms) wurde dann erneut die switch/case-Anweisung mit der neuen Variablen aufgerufen und etwas anderes wurde durchgeführt.


int a=0;
public void Bearbeiten(ref struct SPSein, ref struct SPSaus)
{
   switch (a)
      Case 0:
         //Mache was beim ersten Aufruf
         a=1;
         break;
      Case 1:
         //Mache was beim nächsten Aufruf
         ....

Hierbei verliert man aber irgendwann schnell den Überblick und auch die Durchlaufzeit wird immens hoch. Daher wollte ich nun mehrere Blöcke zusammenfassen.
Jetzt stehe ich aber vor dem folgenden Problem:
Der Methode Bearbeiten übergebe ich den Strukturen der SPS mit ref.


public void Bearbeiten(ref struct SPSein, ref struct SPSaus)
{
   SPSaus.motoran = 1
   // Warte kurz
   if (SPSein.motorläuft==1)
   {
      //hier kommt man beim ersten Aufruf nicht rein
   }
}

Scheinbar werden die Variablen in der struct erst nach dem Verlassen der Methode geändert und nicht sofort, oder irre ich mich da.
Gibt es eine andere Möglichkeit dies zu realisieren?
Vielen Dank für eure Hilfe.

16.834 Beiträge seit 2008
vor 9 Jahren

Doch, die Werte werden sofort geändert; ist schließlich eine Referenz auf das gemeinsame Objekt/Instanz.

1.378 Beiträge seit 2006
vor 9 Jahren

Hallo esparki,

wenn du in deiner Methode "wartest", blockierst du damit vermutlich auch den Aufrufer, der dadurch nicht auf deine Aktion reagieren kann.

Evt. hilfts wenn du die Methode Asynchron gestaltest.

Lg, XXX

C
2.121 Beiträge seit 2010
vor 9 Jahren

Die Werte sind ab dem Zeitpunkt geändert wo man sie setzt.
Kannst du nicht Objekte verwenden? Da gings ohne ref.

Wird der Wert der 1 sein soll tatsächlich vorher gesetzt? Du weißt schon dass du SPSaus.motoran = 1 setzt und im darauf folgenden if etwas ganz anderes abfragst?
Einen sonstigen Zusammenhang sehe ich in deinem Beispiel nicht. Was soll es wie zeigen?

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo esparki,

warum nicht einfach in die MSDN Doku schauen? (Bitte beachte [Hinweis] Wie poste ich richtig? Punkt 1.1 und [Hinweis] Bitte schau in die SDK-/MSDN-Doku.

Das ref-Schlüsselwort bewirkt, dass ein Argument durch einen Verweis und nicht durch seinen Wert übergeben wird. Die Übergabe per Referenz bewirkt, dass jede Änderung des Parameters innerhalb der Methode die zugrunde liegende Argumentvariable der aufrufenden Methode betrifft. Der Wert eines Verweisparameters ist immer der selbe wie der Wert der zugrunde liegenden Argumentvariable.

Außerdem kann man es leicht selbst ausprobieren (öffentliche Felder sollte man regulär nicht verwenden, aber für einen Test geht das in Ordnung):

using System;

static class App
{
   private static A a = new A (5);

   public static void Main ()
   {
      M (ref a.i);
   }

   private static void M (ref int i)
   {
      Console.WriteLine (i);
      Console.WriteLine (a.i);
      i = 20;
      Console.WriteLine (i);
      Console.WriteLine (a.i);
   }
}

public class A
{
   public int i;

   public A (int i)
   {
      this.i = i;
   }
}

Ausgabe:


5
5
20
20

Der Wert der per ref übergebenen Variable ändert sich also direkt und bevor die Methode verlassen wird.

herbivore

W
872 Beiträge seit 2005
vor 9 Jahren

Wenn ich Deinen Code so anschaue, dann halte ich es für wichtiger, daß Du den Struct beibehälst, aber einfach sprechende Variablen wählst oder zum Beispiel neben den ints auch boolsche Variablen oder enums verwendest.


SPSein.motorläuft==1

Switch statements werden sehr schnell abgearbeitet.

16.834 Beiträge seit 2008
vor 9 Jahren

Switch statements werden sehr schnell abgearbeitet.

Wir sollten solche Aussagen mit Sorgfalt genießen; denn switch Statements sind lange nicht soo schnell wie viele denken. Sie sind nur schneller, wenn der Compiler daraus eine Jumptable generieren kann.
Siehe auch if vs switch performance comparison

Wichtiger ist in diesem Fall der lesbarere Code.
Bitte das hier aber nicht diskutieren; zur Not ein extra Thread eröffnen.

F
10.010 Beiträge seit 2004
vor 9 Jahren

@esparki_
Sorry, aber wenn ich "ref struct " sehe, dann bekomme ich Bauchschmerzen.

Wozu meinst du soeinen vollkommen schrecklichen Parameter zu benötigen?
Wir sind hier nicht mehr bei C wo man soetwas brauchte.

16.834 Beiträge seit 2008
vor 9 Jahren

Wird wahrscheinlich daran liegen, dass die 99,9% der Elemente bei SPS eben structs sind und sich die Entwickler daher an diese Art und Weise bei eigenen Dingen gewöhnen.

E
esparki Themenstarter:in
27 Beiträge seit 2006
vor 9 Jahren

Vielen Dank erstmal für die rege Unterstützung

@FZelle: Ich habe den Quellcode von meinem Vorgänger bekommen und arbeite darauf weiter. Aber wie Abt schon richtig vermutet, ist die Bibliothek der SPS schon mit struct aufgebaut.

@weismat und chilic Der Code war nur ein kurz zusammengefasstes Beispiel. Mit dem Ausgang schalte ich den Motor ein und mit dem Eingang frage ich bspw. einen Drehgeber-Sensor ab, der mir sagt, das mein Motor auch wirklich dreht. Die eigentliche Abfrage läuft Byteweise ab (Ein 8fach SPS-Eingangsmodul = 1 Byte), sprich vorher werden die Bytes auf Bits und dann in verständliche Variablen umgewandelt. Da findet dann auch die Umwandlung in bool statt.

@herbivore ich denke mal, so wie die meißten habe ich vor meinem Beitrag auch die MSDN durchforstet und vereinzelt Testcode geschrieben. Leider bin ich nicht auf das passende Ergebnis gekommen.

@xxxprod Genau das habe ich nun gemacht. Ich habe nun die Ein-Ausgabe der SPS und die eigentliche Bearbeitung in zwei verschiedene Threads gepackt. In dem Thread der SPS wird die Input-struct immer mit den aktuellen Daten der SPS beschrieben und die Daten in der Output-struct immer in die SPS-geschrieben. Während die Bearbeitung parallel läuft und auf beide struct zugreift. Um die Zeitverzögerung zwischen dem schreiben in die SPS und ein dafür logisches Eingangssignal zu erhalten verwende ich kurze Schleifen. Hierdurch kann ich auch ein eventuelles hängen in der Anlage abgreifen. Innerhalb der Schleife frage ich auch ab, ob der gewünschte Zsutand schon erreicht ist und springe dann raus um unnötige Wartezeit zu minimieren.


clTimer_TimeOut.Set_ms(150);
while (!clTimer_TimeOut.Abgelaufen())
{
   if(/*logischer Zustand schon erreicht?*/)
        break;
}

Vielen Dank noch einmal für eure schnelle Hilfe.

F
10.010 Beiträge seit 2004
vor 9 Jahren

Aber wie Abt schon richtig vermutet, ist die Bibliothek der SPS schon mit struct aufgebaut.

Was nicht bedeutet das man diesen .. weitermachen muss.

Benutze diese Structs als DTO und benutze ansonsten Klassen, dann musst du diese und viele andere Klimzüge nicht machen.

M
171 Beiträge seit 2012
vor 9 Jahren

Oder nimm gleich die OPCDaAuto.dll - dann brauchst Du garkeine eigene, selbst gebastelte Bibliothek, bei der Du mit irgendwelchen Schleifen auf irgendwas warten musst.