Forum: PC-Programmierung C++/CLI Programmpause


von Christian (Gast)


Lesenswert?

Hallo,
mein Programm kommuniziert über die RS232 Schnittstelle mit einem Gerät.
Zuerst wird ein Befehl gesendet, um Daten anzufordern, dann sendet
das Derät Daten.
Nach dem Sensen muss kurz gewartet werden, bis die Daten kommen.
Da muss das Programm kurz warten.

Mit Tread->Sleep friert mir leider die ganze Oberfläche ein..
Wenn ichs mit Timern mache führt das jetzt ins Chaos, weil dann
Timer den anderen wieder stoppen muss usw.
Gibts irgendeine elegante Variante, die wartet, aber mir nicht das 
Programm einfriert?

von Borislav B. (boris_b)


Lesenswert?

Christian schrieb:
> Mit Tread->Sleep friert mir leider die ganze Oberfläche ein

Du bist lustig. Machst du etwa alles aus einem Thread heraus? Das kann 
nur Ärger geben ;-)

Der richtige Ansatz wäre: Dein Haupt-Thread (GUI) started einen 
Hintergrund-Thread, in welchem die ganze RS232 Geschichte abläuft. Der 
Thread kann dann Sleepen so viel er will, dein Programm bleibt trotzdem 
"responsive". Stichwort "Backgroundworker".

Wenn du dann die GUI updaten willst, kann der Hintergrundthread einfach 
dort hineinrufen, und z.B. Ausgaben anzeigen lassen (Stichwort 
"Invoke").

von Christian (Gast)


Lesenswert?

Hallo,
hm ja das wäre die eleganteste Methode.
Nur blöd, das ich noch nie was mit einem 2. Thread gemacht habe.
Soll ja angeblich ned so einfach sein, auf globale Variablen und so 
zuzugreifen...

von Borislav B. (boris_b)


Lesenswert?

Naja, der Zugriff auf globale Variablen ist im Prinzip schon einfach. 
Schwierig wird's nur, wenn sich beide Threads dann ins Gehege kommen. 
Daher sollte man das vermeiden.

Deswegen würde ich dir raten, deine Architektur so aufzubauen, dass 
beide Threads möglichst unabhängig sind. Globale Variablen gehören 
sowiso nicht zum guten Ton ;-) Ich würde wetten, dass auch ohne 
auskommst. Dann klappt's auch mit dem 2ten Thread...

Falls du konkrete Architektur- bzw. Thread-Fragen hast, wird dir hier 
sicherlich gerne weitergeholfen :-)

von Peter II (Gast)


Lesenswert?

Christian schrieb:
> Nach dem Sensen muss kurz gewartet werden, bis die Daten kommen.
> Da muss das Programm kurz warten.

warum soll denn da gewartet werden? Man empfängt sofort denach die Daten 
und legt einen Tiemout fest bis wann die Daten eintreffen müssen.

von Christian (Gast)


Lesenswert?

Hallo,
gut, dann muss ich das mit den Variablen wohl dementsprechend machen.
Aber mit den Labels habe ich halt noch die Probleme.
ich hab mir das mit dem Invoke schon mal angeschaut, aber ich verstehts 
leider ned...

von Christian (Gast)


Lesenswert?

@Peter II
Bis das Gerät eine Antwort schickt dauerts ein bisschen. Und wenn das 
ganze dann auch noch übers Netzwerk läuft und das ausgelastet ist, 
dauerts schon mal 200 ms bis die Antwort kommt.
Wenn ich dann auslese bevor die Antwort kommt bekomme nichts...

von Borislav B. (boris_b)


Lesenswert?

Christian schrieb:
> ich hab mir das mit dem Invoke schon mal angeschaut, aber ich verstehts
> leider ned...

Eigentlich garnicht so schwer:
Dein 2ter Thread darf nicht einfach so auf die GUI zugreifen. Das darf 
nur der GUI Thread. Wenn Thread 2 also z.B. sowas machen möchte: 
"mLabel1.Text = CoolDataThatWasJustReceived.ToString()" fliegt eine 
Exception.

Deswegen benutzt man den Invoke. Damit kann man sagen, dass ein Stück 
Code auf dem GUI Thread ausgeführt werden soll. Dann gibt's keine 
Probleme.

So sieht das z.B. in C# aus (sehr generisches Beispiel, in deinem Fall 
ist das einfacher):
1
public static void SetControlPropertyThreadSafe(Control control, string propertyName, object propertyValue)
2
{
3
  if (control.InvokeRequired)
4
  {
5
    control.Invoke(new SetControlPropertyThreadSafeDelegate(SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue });
6
  }
7
  else
8
  {
9
    control.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { propertyValue });
10
  }
11
}

von Christian (Gast)


Lesenswert?

Hallo,
könnte mir da jemand ein Beispiel zeigen, wie das jetzt konkret bei
einem Label ausschauen würde?

von Peter II (Gast)


Lesenswert?

Christian schrieb:
> @Peter II
> Bis das Gerät eine Antwort schickt dauerts ein bisschen. Und wenn das
> ganze dann auch noch übers Netzwerk läuft und das ausgelastet ist,
> dauerts schon mal 200 ms bis die Antwort kommt.
> Wenn ich dann auslese bevor die Antwort kommt bekomme nichts...

klar bekommst du nichst. Wo ist das Problem? Wenn du den Timeout auf 10 
Sekunden festlegst, dann ist es egal ob die ersten 200ms nichts kommt.

Wenn du aber fest wartest und die daten kommen mal schneller, dann gehen 
sie im zweifelfall sogar verloren!

von Borislav B. (boris_b)


Lesenswert?

Peter II schrieb:
> klar bekommst du nichst. Wo ist das Problem? Wenn du den Timeout auf 10
> Sekunden festlegst, dann ist es egal ob die ersten 200ms nichts kommt.

Ich denke sein Problem ist, dass der Aufruf zum Empfangen der Daten 
synchron abläuft und daher den GUI Thread lahmlegt.

von Uwe (Gast)


Lesenswert?

Ich denke das er kein Protokoll hat !
Im einfachsten Fall warten bis ein Return kommt für den Zeilenrücklauf.
Falls es nicht innerhalb einer bestimmten Zeit kommt (z.B 10 Sekunden) 
... Timeout. Danach die Daten die Vor dem return sthen verarbeiten.

von Uwe (Gast)


Lesenswert?

Muß dann natürlich blockierend sein und in einem extra Thread laufen, 
wenn er das GUI nicht blockieren will.

von Christian (Gast)


Lesenswert?

Hallo,
ich sende ein Byte und nach dem senden des Bytes muss ich mindestens 
50ms warten, bevor ich den read befehl gebe.
Ansonsten erhalte ich keinen Wert.
Warum und wieso, keine Ahnung.
Timesout habe ich schon.
1
comPort1 = Convert::ToString(totdelport);serialPort1 = gcnew SerialPort(comPort1,9600,Parity::None,8,StopBits::One);
2
serialPort1->ReadTimeout = 1500;
3
serialPort1->Open();
4
  
5
Byte1 = 0x73;
6
Senden[0] = Byte1;
7
serialPort1->Write(Senden,0,1);
8
9
Thread::Sleep(50);
10
11
serialPort1->Read(Empfangen,0,8);

von Peter II (Gast)


Lesenswert?

Christian schrieb:
> ich sende ein Byte und nach dem senden des Bytes muss ich mindestens
> 50ms warten, bevor ich den read befehl gebe.
> Ansonsten erhalte ich keinen Wert.

das ist ziemlich unlogisch. Denn intern macht der computer immer einen 
Read. Nur das es es in einen Puffer einliest. Das würde ich erstmal 
untersuchen in dem du nicht gleich ein read mit 8 zeichen danach machst 
sondern mal einzelen Zeichen einließt. Nicht das noch etwas anderes 
kommt als du erwartest.

von ahellwig (Gast)


Lesenswert?

Christian schrieb:
> Soll ja angeblich ned so einfach sein, auf globale Variablen und so
> zuzugreifen...

C++, also objektorientierte Programmierung, und "globale Variablen" 
beißen sich, aber extrem...

von bluppdidupp (Gast)


Lesenswert?

Christian schrieb:
> könnte mir da jemand ein Beispiel zeigen, wie das jetzt konkret bei
> einem Label ausschauen würde?

Nach der Methode von Boris B einfach aus dem Thread heraus:
SetControlPropertyThreadSafe(NameDesLabelsZBLabel1,"Text","Hallo");
...das entspricht quasi
NameDesLabelsZBLabel1.Text="Hallo";
nur das sichergestellt wird, dass diese Zeile im gleichem Thread 
aufgerufen wird, indem auch NameDesLabelsZBLabel1 erzeugt wurde (sofern 
das Control sagt dass das nötig ist)

Andere Möglichkeiten kann man auch hier finden:
http://stackoverflow.com/questions/2367718/automating-the-invokerequired-code-pattern

Beim BackgroundWorker (eine Art Wrapper-Klasse um einen Thread) kann man 
.ReportProgress() nutzen um Daten an den GUI-Thread zu übermitteln.

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.