Lock funktioniert nicht



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

    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



  • Wie ist denn this.obLoc deklariert ?

    Btw.: Einrücken und die richtigen Codetags verwenden bringt mehr in Sachen lesbarkeit 🤡



  • // ----------------------------------- default constructor ----------------------------------
      public Tcp(){
       // create a new buffer for buffering incoming traffic and set the status to disconnected
       this.lsBuf = new List<byte>(16);
       this.stSta = "Disconnected";
       this.obLoc = new object();
      }
      // ------------------------------------------------------------------------------------------
    

    Sorry wegen dem Einrücken :p



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

    Wie jetzt? Steht das zweite Lock im Ersten?



  • Du hast nicht zufällig mehr als ein Tcp-Objekt?



  • @MFK
    Nein habe ich nicht und ich habe auch die Instanz des internen lockobjects im Debugger mit MakeObjectID überprüft. Es ist dasselbe Objekt 🙄

    @Jockelx
    Der zweite Block ist ein Teil der Methode HandleClient, welche als Delegate an BeginConnect des ersten blockes übergeben wird.

    Das hier habe ich aus der offiziellen Doku entnommen:

    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.



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

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



  • Oh Mann, nix verstehen aber immer gleich rummaulen. Schaaaaaaade Ishildur 🙄

    1. lock() lockt "rekursiv", d.h. du kannst im selben Thread das selbe Objekt mehrfach locken

    2. die BeginXxx Funktionen dürfen den CompletionHandler auch "direkt" aufrufen, also synchron, nämlich dann, wenn der IO sofort abgeschlossen wurde

    Was folgt daraus? Man muss beim Verwenden der BeginXxx Funktionen einfach aufpassen, dass es dem Programm nix ausmacht, wenn eben das passiert.

    Grmpf!



  • @hustbear
    Windoooof war eigentlich mehr im Scherz gedacht (nicht immer alles so ernst nehmen) :p
    Aber dass ich noch nicht viel davon verstehe, stimmt! Ich kenne mich zwar relativ gut mit Multithreading aus, allerdings nicht auf der .NET Plattform. 😉



  • Ich kenne mich zwar relativ gut mit Multithreading aus, allerdings nicht auf der .NET Plattform.

    Spielt denn die Plattform wirklich eine soooo grosse Rolle?
    Simon



  • @theta: naja mann muss schon die Spielregeln der Libraries kennen die man verwendet. Andere Libraries garantieren z.B. dass der Completion-Handler immer asynchron ausgeführt wird, auch wenn die Operation synchron abgeschlossen werden konnte. Das .NET Framework macht es aber anders. Wenn man das nicht weiss, bzw. nicht damit rechnet, fliegt man auf die Schnauze.



  • @hustbaer
    Genau das ist mir passiert 😃 Ich bin davon ausgegangen, dass der Code des delegates niemals ausgeführt werden kann, solange die Initialisierung der Client-/ und Serversockets nicht komplett abgeschlossen ist. Doch genau das passierte eben, wenn die Operation synchron ausgeführt wurde, weil dadurch das lock ausgehebelt wurde 😉

    Ich bedanke mich vielmals für die nützlichen Hinweise



  • "immer asynchron" ist IMO auch der bessere Weg, weil einfacher und daher weniger Fehleranfällig. IMO eine Fehlentscheidung, aber das .NET Framework ist ja geradezu voll davon.


Anmelden zum Antworten