Laden...

Threading

Letzter Beitrag vor 15 Jahren 25 Posts 2.054 Views
Threading

Hallo zusammen
Ich habe ein Problem mit einem Lock: irgendwie scheint das Mutual Exclusion bei C# nicht zu funktionieren? 8o

Erste Codeschnipsel:

// make sure no other thread is currently manipulating the sockets
   lock(this.obLoc){
    // create a server socket and listen for incoming connection attempts
    this.skSrv = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
    //this.skSrv.Bind(new IPEndPoint(this.ipLoc,this.nmPrt));
    //this.skSrv.Listen(1);
    //this.skSrv.BeginAccept(this.HandleServer,null);
    
    // try to establish a client - connection simultaneously
    this.skDta = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
    this.skDta.Bind(new IPEndPoint(this.ipLoc,0));
    this.skDta.Ttl = 10;
    this.skDta.BeginConnect(this.ipRmt,this.nmPrt,this.HandleClient,null);

   // WTF: Zwischen diesen beiden Zeilen wird der komplette Code aus dem zweiten Teil ausgeführt...  ?(

    // adjust the status
    this.stSta = "Connecting to "+this.ipRmt+":"+this.nmPrt;
   }

Zweites Codeschnipsel:

//make sure no other thread is currently manipulating the sockets
   lock(this.obLoc){
    // check if no server connection has been established in the meantime
    if(this.skSrv != null){
     // open a try - statement as an exception may occure
     try{
      // try to end the current client connection process
      this.skDta.EndConnect(Result);

      // close and set null the server - socket immediatly
      this.skSrv.Close();
      this.skSrv = null;

      // adjust the status
      this.stSta = "Connected with "+this.ipRmt+":"+this.nmPrt+" as Client";
     }
     // a socket - exception has occurred
     catch(Exception exp) {
      // make another connection - attempt
      this.skDta.BeginConnect(this.ipRmt,this.nmPrt,this.HandleClient,null);
     }
    }
   }

Leider springt der Code munter von einem Lock ins andere und zurück, wie ist das Möglich?

Mfg Samuel

ich würde spontan behaupten das die beiden thread 2 unterschiedliche instanzen haben?

@JAck30lena
Kannst du mir ein wenig genauer erklären? Wovon sollen sie unterschiedliche Instanzen haben? Also ich instanziere diese Klasse nur einmal!

kannst du bitte die beiden codeteile in die c#-tags einbinden und nciht i ndie zitat-tags? das lässt sich momentan nur schwer lesen

Done 👍

die beiden teile stehen in verschiedenen methoden?

ja, der zweite Teil befindet sich der Methode HandleClient, welche BeginConnect als Delegatemethode übergeben wird

mach mal beim debuggen ein "MakeObjectId" auf this.obLoc und schau mal nach ob er wirklich die selbe instanz lockt.

Habe ich gemacht: Ist dieselbe ID

Ich hatte schon daran gedacht, ob BeginConnect vielleicht das Delegate in demselben Thread aufruft, aber dann hatte ich dies hier entdeckt in der offiziellen Doku entdeckt:

When your application calls BeginConnect, the system will use a separate thread to execute the specified callback method, and will block on EndConnect until the Socket connects successfully or throws an exception.

eigenartig. versuch mal diesen effekt in einer möglichst kurzen konsolenanwendung zu reproduzieren. wenn du es schaffst, es zu reproduzieren, poste bitte den code der konsolenanwendung hier.

So geschafft... Dieser Code erzeugt denselben Fehler, allerdings tritt der Fehler nur im LAN mit einem sehr schnellen Netzwerk auf.

using System;
using System.Net;
using System.Net.Sockets;

namespace Fuck{
 class Program{
  private object obLoc;
  private bool   bErr;

  static void Main(string[] args){
   new Program();
   Console.In.Read();
  }

  public Program(){
   this.obLoc = new object();

   lock(this.obLoc) {
    Socket s = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
    s.Bind(new IPEndPoint(new IPAddress(new byte[] { 192,168,2,6 }),0));
    s.Ttl = 10;
    s.BeginConnect(new IPAddress(new byte[] { 192,168,2,8 }),80,this.HandleClient,null);
    if(this.bErr) Console.WriteLine("Schaaaaade, Windooooooof... Schaaaaade.....");
   }
  }

  private void HandleClient(IAsyncResult Result){
   lock(this.obLoc) {this.bErr = true;}
  }
 }
}

was meinst du damit?

edit: bitte beachte
Wichtig: [Hinweis] Wie poste ich richtig?
Punkt 10

durch deinen edit hast du meine bemerkung den kontext entrissen.

ähhmm... hallo? 🙂

sorry 😉

ich hab den code ein wenig aufpoliert mit debugausgaben. ich konnte jedoch das von dir beschriebene verhalten nciht reproduzieren?

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace etwasAnständiges
{
    internal class Program
    {
        private readonly object obLoc;
        private bool bErr;

        private static void Main(string[] args)
        {
            new Program();
            Console.In.Read();
        }

        public Program()
        {
            obLoc = new object();
            Console.WriteLine("Attempt to enter Lock from:" + Thread.CurrentThread.GetHashCode());
            lock (obLoc)
            {
                Console.WriteLine("Inside Lock from:" + Thread.CurrentThread.GetHashCode());
                Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                s.Bind(new IPEndPoint(new IPAddress(new byte[] {127, 0, 0, 1}), 0));
                s.Ttl = 10;
                s.BeginConnect(new IPAddress(new byte[] {127, 0, 0, 1}), 80, HandleClient, null);
                Thread.Sleep(5000); // do some work
                if (bErr) Console.WriteLine("Schaaaaade, Windooooooof... Schaaaaade.....");
                Console.WriteLine("Leaving Lock from:" + Thread.CurrentThread.GetHashCode());
            }
            Console.WriteLine("Free Lock from:" + Thread.CurrentThread.GetHashCode());
        }

        private void HandleClient(IAsyncResult Result)
        {
            Console.WriteLine("Attempt to enter Lock from:" + Thread.CurrentThread.GetHashCode());
            lock (obLoc)
            {
                Console.WriteLine("Inside Lock from:" + Thread.CurrentThread.GetHashCode());
                bErr = true;
                Console.WriteLine("Leaving Lock from:" + Thread.CurrentThread.GetHashCode());
            }
            Console.WriteLine("Free Lock from:" + Thread.CurrentThread.GetHashCode());
        }
    }
} 

Das ist mein Konsolenoutput

Attempt to enter Lock from:10
Inside Lock from:10
Attempt to enter Lock from:10
Inside Lock from:10
Leaving Lock from:10
Free Lock from:10
Schaaaaade, Windooooooof... Schaaaaade.....
Leaving Lock from:10
Free Lock from:10

interessant... bei dir ist es immer derselbe thread.

edit: mein output:
Attempt to enter Lock from:9
Inside Lock from:9
Attempt to enter Lock from:11
Leaving Lock from:9
Free Lock from:9
Inside Lock from:11
Leaving Lock from:11
Free Lock from:11

Es fällt auf, dass es bei mir derselbe Thread ist 8o

OK, nun ist mir aufgefallen, dass es von Zeit zu Zeit geht. Manchmal sind es unterschiedliche Threads => dann funktionierts. Aber oft ist es derselbe Thread und dann funktionierts natürlich nicht. Die Frage ist nun, warum das Delegate oft in demselben Thread aufgerufen wird...

wie manchmal gehts?
konntest du irgendwelche zusammenhänge feststellen, wann er unterschiedliche threads generiert und wann nciht?

Von 10 Versuchen passiert 9mal ein Fehler und Zusammenhänge konnte ich bislang noch keine feststellen

Etwas ist mir jetzt doch aufgefallen:
Wenn ich die IP von www.google.de 74,125,43,103 anstatt diejenige von meinem Fileserver angebe, dann passiert der Fehler nicht..

Mir kommt es so vor als ob er keinen Separaten Thread für das Callback Delegate verwendet, falls er innerhalb einer sehr sehr kurzen Zeit eine Verbindung aufbauen kann...

Du musst in deinem Code auch EndConnect aufrufen, sonnst bekommst du ein Speicherleck.
Wird wohl so sein, dass unter bestimmten Umständen der Vorgang synchron ausgeführt wird. Um diesen Fall zu erkennen solltest du das IAsyncResult.CompletedSynchronously Property auswerten.

Hallo Zusammen

Laut Doku geht hier schon alles mit rechten Dingen zu. lock() verwendet ja intern einen Monitor. Und in der Monitor.Enter doku steht:

Derselbe Thread kann Enter mehrmals ausführen, ohne dass er blockiert wird.

Ich denke da musst du zusätzlich noch einen boolean nehmen um deinen Fall abzudecken.

Mfg Stefan

@vstm

das lock hier wie erwartet funktioniert, hat auch keiner angezweifelt.