Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von Löwenherz
Thema: Generische Event-Klasse
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo Herbivore,

das ist ganz bestimmt so, nur kann ich mir beim besten Willen nicht vorstellen, wie das gehen soll, da man keine Ableitungen von Delegate oder MulticastDelegate bilden und scheinbar auch nicht explizit auf diese Typen casten kann :-/

*verzweifelt*

Löwenherz

PS: Am liebsten wäre mir natürlich die Lösung mit der generischen Klassen, da man sich damit auch gleich Typsicherheit mit ins Haus holt - und ein Programmierer dann nichts mehr falsch machen kann

Thema: Generische Event-Klasse
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hmmm, das werde ich mir morgen gleich als erstes mal anschauen

Wenn ich das mal rein theoretisch betrachte ... Dann müsste ich überall, wo ich ein Event asynchron abarbeiten will, ja diesen Aufwand mit foreach und BeginInvoke treiben Kann man das nicht etwas kapseln ? ^^

Thema: Netzwerkkarten eindeutig identifizieren
Am im Forum: Netzwerktechnologien

Danke schön für die Antworten :-)

Ich habe mir allerdings schon das WMI Objekt "Win32_NetworkAdapter" angeguckt und eine Position auf dem PCI-Bus ist da leider nicht zu finden

Löwenherz

Thema: Generische Event-Klasse
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Die "normalen" Events unter .NET werden ja sequentiell nacheinander abgearbeitet, und genau das will ich nicht - Ich möchte, dass die Clients des Events asynchron abgearbeitet werden. Und zu allem Überfluss muss das Ding auch noch mit Remoting funktionieren, aber da kümmere ich mich danach drum. Jetzt muss erstmal das asynchrone Event an sich funktionieren.

Löwenherz

Thema: Generische Event-Klasse
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo Forum

Ich hätte mal wieder eine Frage an euch und hoffe, dass ihr vielleicht eine Lösung dafür auf Lager habt :-)

Um es kurz zu machen:
Ich möchte mein Projekt mit Remoting aufziehen und stehe vor dem Problem, dass Remoting nur sehr rudimentäre Event-Unterstützung zu haben scheint. Das wesentliche Problem dürfte die sequentielle Abarbeitung von Aufrufen beim Feuern eines Events sein. Ich möchte die ganzen Aufrufe parallelisieren und jeden Aufruf von einem Threadpool durchführen lassen. Ich habe vor, eine generische Eventklasse zu bauen, die als Parameter den Delegaten übernimmt, der zur aufzurufenden Methode passt, so dass man ein Event einfach nur noch wie folgt erzeugen muss:

Event<MyEventHandler> m_event;

Mein Problem ist nun, wie kann ich das realisieren? ;-)
Die bisherige Event-Klasse seht ihr unten. Mir fehlt vor allem folgendes:
- die Einschränkung des Typs T auf Delegaten
- und eine Methode Fire(), die als Argumente die Argumente des entsprechenden Delegaten hat

Das ist schon eine harte Nuss - zumindest weiß ich spontan nicht, wie ich das machen könnte bzw. ob das überhaupt geht, was ich vorhabe ^^


using System;
using System.Collections.Generic;
using System.Text;

namespace Test
{
  class Event<T>
  {
    private List<T> m_Listener;
    
    public void AttachListener(T listener)
    {
      m_Listener.Add(listener);
    }

    public void DetachListener(T listener)
    {
      m_Listener.Remove(listener);
    }
  }
}

Ich bedanke mich schon einmal im voraus bei euch :-)

Viele Grüße,
Löwenherz

Thema: Netzwerkkarten eindeutig identifizieren
Am im Forum: Netzwerktechnologien

Hallo Borg,

es stimmt alles, was du sagst Die Bilder sind JPEG-komprimiert und die Kameras werden über GBit-Ethernet angeschlossen. Die NICs selbst hängen an PCI Express. Die Bandbreite genügt schon, das ist kein Problem.

Die Kameras kommen mit einer einheitlichen Konfiguration aus dem Lager und die sollte auch niemand mehr anfassen müssen, um ihr eine passende IP-Adresse für Kamera 1 oder 2 zu verpassen. Ich möchte auf das Gehäuse schreiben können "Kamera 1" und "Kamera 2" und dann auch sicher sein, dass dies von der Software so verwendet wird. Mit Hilfe eines selbstgebauten Tools würde ich die passende NIC identifizieren wollen und dann der eine bestimmte IP verpassen. Danach könnte man sich vorstellen, dass man einen DHCP-Server für die Einrichtung der Kameras benutzt.

Für das Herausfinden der PCI-Location (Bus Number, Device Number, Function Number) habe ich allerdings noch keine passende Funktion gefunden. Hast du vielleicht eine Idee, wie ich da rankommen könnte?

Vielen Dank!

Löwenherz

Thema: Netzwerkkarten eindeutig identifizieren
Am im Forum: Netzwerktechnologien

Hallo

Irgendwie habe ich es scheinbar nicht geschafft, das auszudrücken, was ich meine ^^

Die Kameras und die PCs kommen alle ganz identisch aus dem Regal und haben daher alle die gleichen IP-Einstellungen. Die IP-Einstellungen sollen von der Software selbst gemacht werden, um reproduzierbare Ergebnisse zu erhalten. Um nun einer bestimmten NIC eine bestimmte Adresse zuordnen zu können, würde ich gerne wissen, wie man eine bestimmte NIC von anderen NICs im Rechner unterscheiden kann. Die Software soll diese Einstellungen auf allen baugleichen PCs identisch konfigurieren. Also, NIC1 soll z.b. 192.168.1.1 bekommen, NIC2 die 192.168.2.1 usw.

Ich will verhindern, dass durch das Abschalten oder Kaputtgehen einer NIC die Zuweisung "verrutscht". Die MAC-Adresse ist also nicht so gut geeignet, da sie ja logischerweise für jede NIC verschieden ist. Meine Idee war die Identifikation via PCI Bus Number, Device Number und Function Number, also die NICs in ihrer Position im PCI-Bussystem festzuzurren. Fällt nun eine aus, kann man über die Position im Bussystem immer noch eindeutig sagen, welche nun NIC1 ist und welche NIC2.

Die IPs werden kann mit einem eigenen Protokoll vergeben, das DHCP sehr ähnelt.


@GarlandGreene
Ich brauche schon eine NIC für jede Kamera, da da wirklich enorme Datenmengen zustande kommen, wenn man 1600x1200 RGB-Pixel bei ca. 30Hz transportiert.

Thema: Netzwerkkarten eindeutig identifizieren
Am im Forum: Netzwerktechnologien

Hallo und danke für deine schnelle Anwort!

Aber die MAC-Adresse eignet sich für diesen Zweck nicht so gut, da sie eben für jede NIC anders ist Das, was ich suche, ist etwas, mit dem man zwei baugleiche Systeme "aufeinander abbilden" kann.

Nehmen wir mal das Beispiel mit den Kameras. Ich habe zwei Kamera: Kamera 1 und Kamera 2, beide hängen an jeweils einer eigenen Ethernetschnittstelle des PCs. Ich möchte vermeiden, dass die Software, die meine Bildauswertung macht, die Bilder von der falschen Kamera einzieht, wenn man den PC wechselt. Die PCs sind alle baugleich, so dass dies doch ohne weitteres möglich sein müsste...

Meine Sorge ist, dass das eine Windows NIC1 als erste Karte erkennt und das Windows auf dem anderen PC NIC2 als erste Netzwerkkarte nimmt. Gleiches Szenario, wenn NIC1 defekt sein sollte, würde NIC2 doch an dessen stelle rutschen, oder?

Thema: Netzwerkkarten eindeutig identifizieren
Am im Forum: Netzwerktechnologien

Hallo Community

Ich habe hier gerade zwei baugleiche PCs auf dem Tisch und möchte nun in meine Applikation eine Funktion einbauen, die sicherstellt, dass immer ein bestimmter Netzwerkanschluss angesprochen wird. Die beiden Kisten haben jeweils 3 Ethernet-Anschlüsse. Es sind wirklich drei Ethernet-Controller und nicht ein interner Switch

Ich habe schonmal angedacht, das über die PCI Location zu machen, aber in der MSDN habe ich gelesen, dass die PCI Busnummer sich jederzeit ändern kann...

Habt ihr eine Idee, wie ich das Problem angehen könnte?

Zum Background: An jeden dieser Ethernet-Controller kommt genau eine Ethernet-Kamera dran und ich möchte sicherstellen, dass meine Software Kamera 1 auch immer an einem definierten Port findet und nicht mit einem mal Kamera 1 und Kamera 2 den "Platz tauschen"

Ich bedanke mich schon einmal im voraus :-)


Löwenherz

Thema: Spalten im DataGridView auch auf "Nicht-Daten-Bereiche" ausdehnen
Am im Forum: GUI: Windows-Forms

Da hast du sicherlich recht, werde ich mal probieren, danke dir!

Thema: Spalten im DataGridView auch auf "Nicht-Daten-Bereiche" ausdehnen
Am im Forum: GUI: Windows-Forms

Hallo Jack,

erst einmal ein Dankeschön für deine Antwort :-) Aber geht es nicht auch noch anders? Da die Spalten resizable sind, müsste ich bei jeder kleinen Änderung ein neues Bitmap erzeugen. Ist das nicht ein bisschen mit Kanonen auf Spatzen und so ... ?

Thema: Spalten im DataGridView auch auf "Nicht-Daten-Bereiche" ausdehnen
Am im Forum: GUI: Windows-Forms

Hallo Leute :-)

Ich habe in meinem Projekt ein DataGridView, das unter Umständen nur wenige Zeilen enthält. Die Standardhintergrundfarbe ist grau und meine Spalten sind farbig. Jede Spalte hat eine eigene Farbe. Ich möchte nun, dass das DataGridView die Spalten komplett - auch dort wo keine Zeilen mehr sind - in der jeweiligen Spaltenfarbe einfärbt.

Wenn das DataGridView nicht ganz gefüllt ist, sieht das nämlich ziemlich bescheiden aus, wenn unterhalb der gefüllten Zeilen die Spalte die Hintergrundfarbe des Controls hat ;-) Es gibt da bestimmt eine Möglichkeit, die Hintergrundfarbe spaltenweise anzupassen und ich hoffe nun, dass ihr mir da vielleicht weiterhelfen könnt :-)

Vielen Dank schon einmal im voraus!

Löwenherz

Thema: Probleme mit asynchronem TCP-Empfang
Am im Forum: Netzwerktechnologien

Hm, die MSDN sagt folgendes dazu:

Zitat
Bei einem verbindungsorientierten Socket liest die BeginReceive-Methode alle verfügbaren Daten bis zu der Anzahl der Bytes, die im size-Parameter angegeben wurde.

Daher sollte der Buffer eigentlich randvoll gemacht werden, bevor die Callback-Methode aufgerufen wird. Oder hast du vielleicht einen Empfangstimeout eingestellt ?

Thema: Normale Fenstergröße eines maximierten Fensters bestimmen
Am im Forum: GUI: Windows-Forms

*lol*
Dann ist es ja kein Wunder, dass ich auch nichts gefunden habe *g* Aber ich steige demnächst um auf Visual Studio 2005 und dann gibt es auch .NET 2.0 mit der passenden Methode. Juchuu :-)

Danke!

Thema: Probleme mit asynchronem TCP-Empfang
Am im Forum: Netzwerktechnologien

Hmm, was spricht dagegen, ein unvollständiges Paket zu puffern und mit dem nächsten Schwung an Daten zu interpretieren?

Thema: Probleme mit asynchronem TCP-Empfang
Am im Forum: Netzwerktechnologien

Zitat
Der Puffer hat eine Länge von (mittlerweile) 4096 Byte.
Dann wird BeginReceive() versuchen, die 4096 Bytes auf vollzubekommen. Und das geht nicht, wenn du nur 9 bis 50 Bytes pro Datenstruktur, die du versendest, hast. Hast du mal probiert, die Anzahl der zu empfangenden Bytes auf die Größe eines Pakets zu reduzieren?

Thema: Normale Fenstergröße eines maximierten Fensters bestimmen
Am im Forum: GUI: Windows-Forms

Hallo Leute :-)

Ich knobel gerade an der Aufgabe rum, wie ich am besten die Abmessungen eines Forms speichern kann. Ich möchte einerseits den WindowState (Normal, Minimized, Maximized) speichern, als auch die Abmessungen des NICHT-maximierten Fensters, wenn das Fenster gerade im maximierten Modus ist. Rufe ich im Falle eines maximierten Fensters Control.Bounds() auf, so bekomme ich natürlich die maximierten Abmessungen, aber nicht die des normalen Fensters, das erscheint, wenn ich "maximiert" wieder wegnehme.

Bisher mache ich das so:


subkey.SetValue("Windowstate", (int) WindowState);
WindowState = FormWindowState.Normal;
subkey.SetValue("Bounds (x)", Bounds.X);
subkey.SetValue("Bounds (y)", Bounds.Y);
subkey.SetValue("Bounds (cx)", Bounds.Width);
subkey.SetValue("Bounds (cy)", Bounds.Height);

Der Wermutstropfen ist nun aber, dass das Fenster sich erstmal sichtbar in den Normal-Modus fährt, bevor es sich schließt... und das ist irgendwie unnötig.

Wie komme ich denn sonst noch an die normale Fenstergröße eines maximierten Forms oder allgemein Controls?

Vielen Dank!

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Hm, tun die Ereignisse (Messages) ja auch nicht, die werden halt gequeued und später abgearbeitet. Irgendwie ist das ein toller Fall mit Laufzeitproblemen, für den man nur einen Thread haben muss

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Achso, mir fällt da noch was zur Ergänzung ein...

Ersetze doch mal den MessageBox.Show()-Aufruf durch einen Aufruf von Form.ShowDialog(). Das gibt das gleiche Problem. Der Witz ist irgendwie die Implementierung von modalen Dialogfenstern in .NET.

Wenn du die besagte Zeile aber durch ein Thread.Sleep() oder ein AutoResetEvent (z.B. m_event.WaitOnE(1000, false)) ersetzt. Dann blockiert der GUI-Thread wirklich und es ist alles so wie ich es erwarten würde. Nur diese bekloppten modalen Forms machen da echt Ärger... warum auch immer ;-)

Herbivore hat in einem anderen Thread hier auch schonmal darauf hingewiesen, dass MessageBoxes beim Debuggen das allerletzte sind. Ich glaube, ich weiß jetzt auch, wieso

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Hmm, ok

Ich glaube, dann habe ich es verstanden - glaube ich. Danke dir!

Auch wenn in den CodeProject-Artikel steht, dass es eine Messageloop intern gibt, die die PostMessage-Messages abarbeitet. Und solange der Handler einer dieser Messages noch nicht vollständig durchgelaufen ist, sollte die nächste warten müssen. Daher kam so das Problem auf ^^

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Hallo nochmal und sorry, dass ich euch erneut behelligen muss ;-)

Schaut euch mal bitte das folgende kleine Testprogramm an. Es reproduziert genau den Fehler, den ich meinte.


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using System.Diagnostics;

namespace TestApp
{
	/// <summary>
	/// Zusammenfassung für Form1.
	/// </summary>
	public class Form1 : System.Windows.Forms.Form
	{
		/// <summary>
		/// Erforderliche Designervariable.
		/// </summary>
		private System.ComponentModel.Container components = null;
    private Thread thread1;
    private Thread thread2;
    private Thread thread3;
    private System.Windows.Forms.Button m_ButtonStart;

		public Form1()
		{
			InitializeComponent();
      Thread.CurrentThread.Name = "GUI Thread";
		}

		/// <summary>
		/// Die verwendeten Ressourcen bereinigen.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )	{
				if (components != null) {
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Vom Windows Form-Designer generierter Code
		/// <summary>
		/// Erforderliche Methode für die Designerunterstützung. 
		/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
		/// </summary>
		private void InitializeComponent()
		{
      this.m_ButtonStart = new System.Windows.Forms.Button();
      this.SuspendLayout();
      // 
      // m_ButtonStart
      // 
      this.m_ButtonStart.Location = new System.Drawing.Point(96, 112);
      this.m_ButtonStart.Name = "m_ButtonStart";
      this.m_ButtonStart.TabIndex = 0;
      this.m_ButtonStart.Text = "Start";
      this.m_ButtonStart.Click += new System.EventHandler(this.m_ButtonStart_Click);
      // 
      // Form1
      // 
      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
      this.ClientSize = new System.Drawing.Size(292, 266);
      this.Controls.Add(this.m_ButtonStart);
      this.Name = "Form1";
      this.Text = "Form1";
      this.ResumeLayout(false);

    }
		#endregion

    private delegate void VoidDelegate();

    private void ThreadProc1()
    {
      Thread.CurrentThread.Name = "Thread 1";
      this.Invoke(new VoidDelegate(Print));
    }

    private void ThreadProc2()
    {
      Thread.CurrentThread.Name = "Thread 2";
      this.Invoke(new VoidDelegate(Print));
    }

    private void ThreadProc3()
    {
      Thread.CurrentThread.Name = "Thread 3";
      this.Invoke(new VoidDelegate(Print));
    }

    private void Print()
    {
      Debug.WriteLine("--- Print started: " + Thread.CurrentThread.Name + " ---");
      for(int i=0; i < 15; i++) {
        Debug.WriteLine("Line " + i);
        if (i == 10) MessageBox.Show("Es ist die 10. Runde!");
      }
      Debug.WriteLine("--- Print stopped: " + Thread.CurrentThread.Name + " ---");
    }

		/// <summary>
		/// Der Haupteinstiegspunkt für die Anwendung.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new Form1());
		}

    private void m_ButtonStart_Click(object sender, System.EventArgs e)
    {
      thread1 = new Thread(new ThreadStart(ThreadProc1));
      thread2 = new Thread(new ThreadStart(ThreadProc2));
      thread3 = new Thread(new ThreadStart(ThreadProc3));
      thread1.Start();
      thread2.Start();
      thread3.Start();
    }
	}
}

Im Log steht dann folgendes:


--- Print started: GUI Thread ---
Line 0
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10
--- Print started: GUI Thread ---
Line 0
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10
--- Print started: GUI Thread ---
Line 0
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10
Line 11
Line 12
Line 13
Line 14
--- Print stopped: GUI Thread ---
Der Thread 'Thread 2' (0xa98) hat mit Code 0 (0x0) geendet.
Line 11
Line 12
Line 13
Line 14
--- Print stopped: GUI Thread ---
Der Thread 'Thread 3' (0xbf4) hat mit Code 0 (0x0) geendet.
Line 11
Line 12
Line 13
Line 14
--- Print stopped: GUI Thread ---
Der Thread 'Thread 1' (0x29c) hat mit Code 0 (0x0) geendet.

Noch während ich mich mit meinem GUI-Thread in der Ausführung von Print() befinde, wechselt die Kontrolle und der GUI-Thread beginnt die Print()-Methode erneut. Wie kann das denn sein, wenn Control.Invoke() und Control.BeginInvoke() angeblich nichts weiter tun, als eine Message in die Messagequeue des Steuerelements einzuhängen?!

Ich werde daraus echt nicht schlau, sorry :-(

Aber vielleicht kann mir ja eine(r) von euch sagen, wo ich da den Knoten im Denkapparat habe

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

:-D

Eigentlich gar nichts. Wir haben es offenbar nur geschafft aneinander vorbei zu diskutieren ^^

Und wie du schon sagst, es wird immer der GUI-Thread arbeiten. Der Witz ist aber, dass in meiner Applikation (scheinbar) im Kontext des GUI-Threads die aufgerufene Methode angefangen, unterbrochen, vom anderen Thread gestartet, wieder unterbrochen und dann zuende gelaufen ist. Das Problem ist bei mir der Wechsel des Kontextes _während_ der Ausführung der Methode, obwohl ich BeginInvoke benutzt habe.

Die Grundlagen und wie BeginInvoke funktionieren sollte sind mir klar, aber das resultierende Verhalten (s.o.) hat mich echt fertig gemacht ^^ Ich glaube, ich schaue mir das morgen nochmal gaaaaaanz genau an. Kann ja nicht so schwer sein Ich habe sicherlich nur irgendwas übersehen.

Ich danke euch auf jeden Fall für die vielen Antworten! :shakehands:

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Zitat
Original von Traumzauberbaum
Du verstehst da glaub ich Synchronisation falsch.

Die Nachrichten werden in den GUI Thread auch genau in der Reihenfolge ausgewertet wie du sie reinsteckst. Nur hat das mit Synchronisation herzlich wenig zu tun.

Genau das passiert bei dir auch.

Synchronisation heißt grob gesagt, dass ein Thread auf einen anderen wartet.

Und genau das ist das Problem bei dir.

Das Geschehen läuft in 2 Threads ab, keiner wartet auf den anderen.
Der eine startet ohne auf das Beenden des Anderen zu warten. Also kommt der Aufruf zum Start des 2. vor dem beenden des 1. Also kommt auch in die MessageQueue erst die 2. Meldung vom Start, bevor einer das Beenden meldet.

Kannst dir doch mal die Uhrzeit/Tickcount anschauen, bei denen jeweils Anfang und Ende gemeldet werden.

Joa, das ist alles richtig, sehe ich auch so. Aber das betrifft eher 2 Threads, die "einfach so" (ohne Messagequeue) miteinander interagieren. Wenn ich eine Messagequeue habe, muss der aufrufende Thread doch eigentlich nur noch eine Message in die Queue stecken und die aufzurufende Methode wird dann ausgeführt, wenn der GUI-Thread die Message abholt und dann abarbeitet. Hmmm :confused:

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Zitat
Original von MarsStein
@Löwenherz
Wenn Du denvon Dir geposteten Artikel bei codeproject richtig gelesen hast, müsste Dein Problemeigentlich klar geworden sein. Ich halte den Artikel auch für sehr gut. Du scheinst an dieser Stelle noch ein grundsätzliches Verständnisproblem zu haben, lies den Artikel nochmal genau durch. Dann siehst Du, daß Du in DeinemFall entweder mit Invoke() arbeitenen solltest, oder Deine Threads eben manuell synchronisieren musst.

Sorry, ich habe nicht richtig geantwortet...
Ich habe den Artikel aufmerksam gelesen und der besagte genau das, was ich auch angenommen habe.

Mal eine Frage ... Was sollte BeginInvoke() denn sonst bringen, wenn nicht die Kontrolle an einen anderen Thread zu übergeben? Und da der GUI-Thread ja intern messagebasiert arbeitet, führt das mE zwangsweise zu einer Synchronisation.

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Joa, das kann gut sein. Ich habe eben noch ein bissl mit dem Problem experimentiert.
Folgender Code läuft bei mir wie gewünscht ab, und zwar so, dass die Print()-Methode nicht unterbrochen wird und sauber von Anfang bei Ende durchläuft, bevor sie eine neue Runde dreht und die Anforderung vom anderen Thread bedient. *verzweifel*


using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace BeginInvokeTest
{
  class Program : Form
  {
    private Thread thread1;
    private Thread thread2;

    Program()
    {
      Thread.CurrentThread.Name = "GUI Thread";
      thread1 = new Thread(new ThreadStart(ThreadProc1));
      thread2 = new Thread(new ThreadStart(ThreadProc2));
      thread1.Start();
      thread2.Start();
    }

    ~Program()
    {
      thread1.Join();
      thread2.Join();
    }

    private delegate void PrintDelegate(string s);

    private void ThreadProc1()
    {
      Thread.CurrentThread.Name = "ThreadProc1";
      while (true)
      {
        if (this.Created) this.BeginInvoke(new PrintDelegate(Print), new object[] { "Ich bin ThreadProc1" });
        Thread.Sleep(500);
      }
    }

    private void ThreadProc2()
    {
      Thread.CurrentThread.Name = "ThreadProc2";
      while (true)
      {
        if (this.Created) this.BeginInvoke(new PrintDelegate(Print), new object[] { "Ich bin ThreadProc2" });
        Thread.Sleep(500);
      }
    }

    void Print(string s)
    {
      Console.WriteLine(Thread.CurrentThread.Name + " [Anfang] - " + s);
      for (int i = 0; i < 10; i++) {
        Console.WriteLine(Thread.CurrentThread.Name + " - " + i);
        Thread.Sleep(0);
      }
      Console.WriteLine(Thread.CurrentThread.Name + " [Ende] - " + s);
    }


    static void Main(string[] args)
    {
      Program prog = new Program();
      Application.Run(prog);
    }
  }
}

Und das bildet eigentlich genau mein Problem nach, was ich mit Socket.BeginConnect und anschließendem Control.BeginInvoke zu haben scheine *g* Oh Mann

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Zitat
Original von MarsStein
Hallo,
Zitat
nur leider war die ganze Geschichte dann nicht mehr synchron
wie denn auch? Du hast es ja explizit asynchron aufgerufen!! Wenn Du das wieder synchron habe willst, verweise ich nochmal auf die Verwendung von lock (siehe mein letzter Post).
Zitat
und ich weiß leider nicht, wie ich die Thread-ID rausbekomme
mit Thread.CurrentThread kommst Du immer an den gerade laufenden Thread.

Hmm, ja ^^

Die Asynchronität sollte meines Erachtens nach beim Control.BeginInvoke() enden, da das ja eine Window-Message in die Messagequeue des GUI-Threads postet. Das versuche ich ja die ganze Zeit klarzumachen. So steht es zumindest bei
http://www.codeproject.com/csharp/begininvoke.asp

Und mit Thread.CurrentThread hast du schon recht, aber da komme ich höchstens an einen Namen mittels Thread.Name. Eine ID gibt es leider nicht. Wenn du mir aber sagen kannst, wie ich einem Thread aus dem Threadpool einen Namen zuordne, wäre ich aus dem Schneider :-)

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Die asynchronen Aufrufe mit BeginConnect() habe ich genommen, damit mir mein GUI-Thread nicht blockiert, wenn er keinen Connect hinbekommt und irgendwann mit einem Timeout wiederkommt. Die Applikation sieht dann ziemlich abgestürzt aus, was sie aber nicht ist.

Und das Control.BeginInvoke() wollte ich eigentlich nur mal ausprobieren und war verwundert, wieso es nicht ging Verstanden habe ich das mit Problem mit Control.BeginInvoke() leider immer noch nicht.

Ich habe mir das Ding hier mal durchgelesen:
http://www.codeproject.com/csharp/begininvoke.asp

... und musste feststellen, dass die Callback-Methoden der Socket.BeginConnect()-Methode mit Control.BeginInvoke() im GUI-Thread per Window-Message die gewünschte Methode anstoßen sollten. Haben sie ja auch, nur leider war die ganze Geschichte dann nicht mehr synchron und ich weiß leider nicht, wie ich die Thread-ID rausbekomme, sonst hätte ich da einfach mal ein Debug.WriteLine() mit der Thread-ID reingebastelt, um rauszubekommen, wer denn da meine GUI-Methode aufruft ^^

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Ja, ist leider nötig, da ich meinen GUI-Thread unter keinen Umständen blockieren darf.

Und unübersichtlich finde ich das auch irgendwie nicht. Eigentlich ist es doch ganz einfach. Ich verstehe nur nicht, wieso das nicht so funktioniert *g*

- BeginConnect() startet einen Thread aus dem Threadpool und lässt die Connect-Operation darin laufen
- Callback-Methode wird von diesem Thread aufgerufen
- Innerhalb der Callback-Methode packe ich mit BeginInvoke() eine Message in die Messagequeue von meinem GUI-Thread
- GUI-Thread arbeitet die Message irgendwann ab, wenn sie dran ist.

Das sieht für mich doch nach einer definierten Reihenfolge aus. Durch das Posten einer Message in BeginInvoke() sequentialisiert sich doch die gesamte Ausführung. Zumindest meinem Verständnis nach

Bitte korrigiert mich, wenn ich da falsch liege.

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Erst einmal vielen Dank für eure Antworten!

Zitat
Original von MarsStein
Hallo,
wen ich das jetzt richtig verstanden habe passiert folgendes:
Zitat
Ich starte mit Socket.BeginConnect() zwei Verbindungsversuche
Durch den asynchronén Connect-Aufruf werden 2 Threads gestartet, die jeweils versuchen sich zu verbinden.
Jeder dieser Threads ruft dann Dein Callback-Funktion. In dieser wird wiederum mit "BeginInvoke" ein asynchroner Aufruf gestartet, so daß die Methode, die über BeginInvoke ausgeführt wird, zwiemal gerufen wird.
Da aber bereits das BeginConnect asynchron ausgeführt wird, kommt es vermutlich zu folgender (oder ähnlicher) Reihenfolge bei der Ausführung

BeginConnect1
Callbackaufruf1 -> ruft BeginInvoke -> Ausgabe ANFANG
BeginConnect2
Callbackaufruf2 -> ruft BeginInvoke -> Ausgabe ANFANG
Ende Invoke1 -> Ausgabe ENDE
EndeCallback1
Ende Invoke2 -> Ausgabe ENDE
EndeCallback2

Musst Du dich eigentlich gleich 2mal connecten oder könntest du evtl. die beiden Connect synchron hintereinander ausführen?

Hmm, so habe ich das anfangs auch gedacht. Aber wie svenson auch geschrieben hat, wird die Ausführung dieser beiden aufgerufenen Delegaten im GUI Thread nacheinander ausgeführt. Daher müsste meines Erachtens nach doch zuerst der erste Aufruf im GUI-Thread komplett durchlaufen, bevor der zweite Aufruf abgearbeitet werden kann. Ich habe gelesen, dass BeginInvoke und Invoke mit der API-Funktion PostMessage() implementiert sind und daher ja auch nacheinander ausgeführt werden müssten. Aber genau das scheint nicht zu klappen. Sehr seltsam ... *nachdenklich am Kopf kratz*

Thema: Control.BeginInvoke und Racing Conditions
Am im Forum: GUI: Windows-Forms

Hallo Leute :-)

Ich habe da ein ganz besonderes Leckerli, an dem ich schon ein paar Stunden rumlaboriere ^^ Ich starte mit Socket.BeginConnect() zwei Verbindungsversuche zu einem Host im Netzwerk. Die Callback-Methode, die bei Erfolg oder Misserfolg aufgerufen wird, läuft in einem Thread des Threadpools, wenn ich das recht verstanden habe. Da meine GUI aber auch etwas davon mitbekommen soll, habe ich in dieser Callback-Methode Control.BeginInvoke() benutzt, um meinen GUI-Thread über den Ausgang des Verbindungsaufbaus zu informieren.

An Anfang und Ende dieser Methode, die im Context des GUI-Threads läuft, habe ich eine Meldung eingebaut, die dann ins Log geschrieben wird. Lustigerweise kommt folgendes dabei raus:

ANFANG
ANFANG
ENDE
ENDE

d.h. der GUI-Thread unterbricht irgendwo in der Mitte der Methode die Ausführung und "beginnt von vorn". Irgendwann läuft die erste Ausführung dann weiter. Das ist doch völlig unmöglich, wenn ich Control.BeginInvoke() zum Aufruf dieser GUI-Methode benutze, oder?

Nebenbei... Mit Constrol.Invoke(), statt mit control.BeginInvoke() läuft die Kiste... seeeehr seltsam.

Ich hoffe, jemand von euch hatte so ein Problem schon einmal und kann mir sagen, woran es liegt.

Vielen Dank schon einmal im vorraus!