C# - Aus Thread eine Funktion ausrufen

Gast #4432197
Lesenswert?

Ich habe ein Programm, welches mir in einem Thread einen UDP String 
ausließt. Nun würde ich gerne durch diesen Thread eine externe Funktion 
starten, welche nicht in diesem Thread läuft.

Wie stelle ich das am dümmsten an.

Einen Wert kann ich ja mit invoke bzw. invokeRequired übergeben. Ich 
möchte halt aber einfach nur eine Funktion "anstoßen".
Gast #4432206
Lesenswert?

Draco schrieb:
> Nun würde ich gerne durch diesen Thread eine externe Funktion
> starten, welche nicht in diesem Thread läuft.

was soll das heißen "welche nicht in diesem Thread läuft"?

eine Funktion läuft in dem Thread wo sie gestartet wird. Was hindert 
dich daran also die Funktion einfach zu starten?
#4432529
Lesenswert?

Hallo,

da gibt es zwei Möglickeiten:

1. permanent laufender Thread
eine Callback Funktion kann Dir jedesmal den String an eine andere 
Stelle in Deinem Programm übergeben.

2. Abgeleitete Thread-Klasse und nur einmal laufend
Property declarieren und im OnComplete des Thread setzen. Anschließend 
im Programm abfragen.

Gruß
Frank
#4433254
Lesenswert?

Könnten Sie bitte etwas Code mitposten/uploaden? Sie müssen nicht Alles 
posten. Es reicht nur den Funktionskopf + "..." + den Return-Anweisung + 
etwas genauere Beschreibung zu Posten, was (nochmal Funktoinskopf +/- 
Klassen-Schnittstellen) Ihre UDP-Lese-Thread starten möchte.

Soweit ich Sie verstanden habe...

Sie haben ein Program "P", welches einen Thread "T" startet.
"T" liest ein UDP Packet aus und erzeugt ein Objekt (von bel. Typ), 
welches die Daten des UDP-Packets in sich trägt.
Und nun möchten Sie, dass dieses Objekt von "T" an "P" zurückgegeben 
wird? Stimmt das so?

Falls ich Sie richtig verstanden habe, dann können Sie z.B. so diesen 
Wert (für alle Interessenten) aktualisieren:
1
public class XYZ
2
{
3
/*
4
   Deklariert den Signatur von Methoden die sich bei Event (unten),
5
   zwecks Benachrichtigung, registrieren können.
6
*/
7
public delegate UdpChangedEvent(MyUdp pMyUdp);
8

9
/*
10
  Wird aufgerufen/angestoßen, wenn sich der Eigenschaft-Wert "UDP" (weiter unten) ändert.
11
*/
12
public event UdpChangedEvent UdpChanged;
13

14
private void NotifyUdpChanged(MyUdp pMyUdp)
15
{
16
   if(UdpChanged != null)
17
      UdpChanged(pMyUdp);
18
}
19

20
private MyUDP udp = null;
21

22
/*
23
   Eigenschaft.
24
*/
25
public MyUDP UDP
26
{
27
   get { return udp; }
28
   set
29
   {
30
      if(udp == value)
31
         return;
32

33
      udp = value;
34
      NotifyUdpChanged(udp);
35
   }
36
}
37

38

39
/* Und so kann/können der/die Interessent(en) sich registrieren, um von Änderung des UDP-Wertes automatisch benachichtigt zu werden... */
40

41
var xyz = new XYZ();
42
xyz.UdpChanged += Die_Handler_Methode;
43

44
/* Und "Die_Handler_Methode" ist nun überall dort wo man benachrichtigt und dann etwas machen möchte */
45
private void Die_Handler_Methode(MyUDP myUdp)
46
{
47
   Console.WriteLine(myUdp);
48
   // udg. usw. usf.
49
}
Persönliche Seite #4434103
Lesenswert?

Hab ein ähnliches Problem gehabt mit unterschiedlichen Threads zwar im 
selben Programm, aber die Delegaten (direkt aufgerufen) haben mich 
allein gelassen.

Ich habs mit Action gelöst aus dem einen Workerthread ins Formular dann 
aufgerufen.

Die Empfangsfunktion existiert im Formular:
public void Method1(int x) ...

Im Workerthread:
Action<int> action = new Action<int>(Method1,5);
Formular.Invoke(action);
Persönliche Seite #4434205
Lesenswert?

Mal ein Funktionelles Beispiel

Die Empfangsfunktion existiert im Formular:
public partial class MainForm : Form
{
 private Class1 cl1=new Class1();
 public MainForm() {
  InitializeComponent();
  this.backgroundWorker1.DoWork += new DoWorkEventHandler(cl1.DoWork);
 }
 public void CallBack(int i) {
  button1.BackColor=Color.Yellow;
 }
 void Button1Click(object sender, EventArgs e) {
  if(!backgroundWorker1.IsBusy) {
   button1.BackColor=Color.Green;
   backgroundWorker1.RunWorkerAsync(this);
  }
 }
 public class MyDoWorkEventArgs {
  public MainForm mf;
  public MyDoWorkEventArgs(MainForm mf) {
   this.mf=mf;
  }
 }
}

Dem Workerthread muß man allerdings als Argument auch das 
Formular-Object übergeben.
Im Workerthread/Class1:
public class Class1
{
  public void DoWork(object sender, DoWorkEventArgs e) {
    Thread.Sleep(1000);
    MainForm mf=e.Argument as MainForm;
    mf.Invoke(new Action<int>(mf.CallBack),5);
  }
}
#4434245
Lesenswert?

Leute Leute,

wenn Ihr schon Vorschläge bringt, dann macht es direkt richtig.

Einen Callback in den Formularthread kann man ganz gemütlich mit ein 
paar Zeilen Code abfrühstücken.
1
//  muss der Eventnotation entsprechen
2
private delegate void EventCallbackDelegate(string value)
3
private void EventCallbackExecute(string value)
4
{
5
// hier das eigentliche Doing
6
}
7

8
private void EventCallback(string value)
9
{
10
  if (InvokeRequired)
11
  {
12
    Invoke(new EventCallbackDelegate(EventCallbackExecute), value);
13
    return;
14
  }
15
  EventCallbackExecute(value)
16
}

Registriert wird die Funktion EventCallback in der Klasse, wo sie 
aufgerufen werden soll. Hier z.B. im Thread und oder in anderen Klassen.

Auf diese Weise kann der Callback ohne Probleme in Task oder Thread oder 
Backgroundworker verwendet werden.

Ganz elegant funktioniert das ganze dann mit Task, await und async.

Gruß
Frank
Gast #4434553
Lesenswert?

Danke Leute, das was Frank gepostet hat, war das was ich gesucht habe. 
Aber es ist schön zu sehen das es ja doch mehrere Möglichkeiten gibt 
solch ein Problem anzugehen.

Das Problem war jenes, das ich in dem eigentlich Thread zu auslesen, 
nicht die Berechnung durchführen lassen wollte. Die Übergabe an 
Formularinhalte aber enorme Invoke Ausmaße angenommen hatte.

Ich hatte mir dann als "Zwischenbehelf" ein TimerObject angelegt welches 
regelmäßig prüft ob denn ein neues Paket empfangen wurde und dies dann 
abarbeitete. Das ist natürlich aus Sicht der Performance, den 
Möglichkeiten und des Code-Designs absoluter Dünschiss, aber es hatte 
funktioniert :D So in etwa:

1
//....
2
volatail bool isSet = false;
3
//....
4
Listener = new Thread(UDP_Listener);
5
Listener.start();
6
//....
7

8
public void UDP_Listener()
9
{
10
   //....
11
   bool done = false;
12
   while (!done)
13
   {
14
     //...
15
     isSet = true;
16
   }
17
}
18

19

20

21
private void tim_UDP_Tick(object sender, EventArgs e)
22
{
23
   if(isSet)
24
   {
25
      //Hier die Berechnung und die Ausgabe ausführen
26
   }      
27
}
28

29
//....

Den Timer habe ich alle 10ms aufrufen lassen, egal ob ich Daten bekommen 
hatte oder nicht.

Keine Angst, hab ich nun natürlich ersetzt. :)
Gast #4434569
Lesenswert?

Draco schrieb:
> Das Problem war jenes, das ich in dem eigentlich Thread zu auslesen,
> nicht die Berechnung durchführen lassen wollte.

hättest du das nicht gleich schreiben können?

Ich würde für die Berechnung einen eigenen Threads schreiben. Die 
UDP-Daten werden in ein Liste (Queue) gesteckt und der Thread mit einen 
Event geweckt.

Der Thread prüft in eine Endlosschleife ob Daten in der Queue vorhanden 
sind, wenn nein wartet er auf das Event.

Das muss braucht man nur eine ein Lock auf die Liste und ein Event 
objekt. Das ganze invoke braucht man dann nicht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren