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".
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?
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
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
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
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
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); } }
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
@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.
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. :)
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.