Forum: PC-Programmierung C# - Aus Thread eine Funktion ausrufen


von Draco (Gast)


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".

von Peter II (Gast)


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?

von Frank L. (frank_l)


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

von Fuzzi59 (Gast)


Lesenswert?

Das hört sich so an, als wölltest du eine Methode asynchron aufrufen. 
Dafür solltest du dir mal folgende Seite ansehen: 
http://openbook.rheinwerk-verlag.de/visual_csharp_2012/1997_15_002.html#dodtp6cd94ef0-9aae-45b1-9de3-f66b3125d6e4

von Pedram G. (ganjeh_hadidi)


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
}

: Bearbeitet durch User
von Dennis H. (c-logic) Benutzerseite


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);

: Bearbeitet durch User
von Dennis H. (c-logic) Benutzerseite


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);
  }
}

von Frank L. (frank_l)


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

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

@Frank L:

Hab gerade mal ausprobiert.
Die Variante funktioniert auch.

Problem bei mir war, daß der BackgroundWorker in einer anderen Klasse.

Variante 1:
mf.Invoke(new Action<int>(mf.CallBack),5);

macht automatisch ein delegate draus.

Variante 2: (Frank)
mf.Invoke(new MainForm.EventCallbackDelegate(mf.CallBack),5);

Machen beide das gleiche.

von Draco (Gast)


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. :)

von Peter II (Gast)


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.

von Horst (Gast)


Lesenswert?

Falls du einen Ansatz zum Suchen brauchst: Producer Consumer Queue.

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.