none
Dateien gelockt öffnen, ändern, schreiben RRS feed

  • Frage

  • Hallo Community,

    Ich habe derzeit folgende XML-Datei:

    <?xml version="1.0" encoding="utf-8" ?>
    <Root>
      <Counters>
        <Counter>
          <Name = "Gerade" value = "8" </Name>
        </Cursor>
        <Counter>
          <Name = "Ungerade" value = "77" </Name>
        </Cursor>
        <Counter>
          <Name = "Test" value = "1000" </Name>
        </Counter>
      </Counters>
    </Root>

    Weiterhin habe ich eine Applikation - Zaehler.EXE, die ich drei mal öffne und eine Datei.

    Counters.XML

    Alle drei Applikationen greifen auf diese zu und erhöhen die Zählerstände, jeweils um 1

    Idee: Den Zähler 'Test' möchte ich von allen 3 Applikationen zeitgleich um 100 Durchläufe erhöhen.

    Wenn alles passt, alle durchlaufen sind, muss ich den Zählerstand 1300 haben.

    Wer kann mit Tipps, für diese Testanwendung geben? Danke im Voraus.

    Thread? locking? Mutex?  Exclusiv öffnen?

    Viele Grüße Martin


    • Bearbeitet Martin Scheid Dienstag, 29. November 2016 11:38 Korrektur im XML
    Dienstag, 29. November 2016 11:36

Antworten

  • Hi Martin,

    eine weitere Möglichkeit wäre eine Inter-Process  Communication.

    Eine Art wäre dass du eine Server Applikation hast die die Datei ließt und schreibt d.h. die Synchronisation übernimmt und beliebig viele Client Applikationen die den Server beauftragen die Zahl zu inkrementieren.

    -------

    Server:

    class Program
    {
        static void Send(NamedPipeClientStream client, Message data)
        {
            StreamString ss = new StreamString(client);
            var messageString = new JavaScriptSerializer().Serialize(data);
            Console.WriteLine("Send message: " + messageString);
            ss.WriteString(messageString);
        }
    
        static Message Receive(NamedPipeClientStream client)
        {
            StreamString ss = new StreamString(client);
            string messageString = ss.ReadString();
            Console.WriteLine("Receive message: " + messageString);
            return new JavaScriptSerializer().Deserialize<Message>(messageString);
        }
    
        static void Main(string[] args)
        {
            string filePath = "SomeFile.xml";
            var client = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut);
            try
            {
                client.Connect();
    
                var message = new Message();
                message.FilePath = filePath;
                Send(client, message);
    
                var response = Receive(client);
                var data = int.Parse(response.Data);
                data = data + 100;
    
                message = new Message();
                message.FilePath = filePath;
                message.Data = data.ToString();
                Send(client, message);
            }
            finally
            {
                client.Close();
            }
        }
    }

    Message:

    public class Message
    {
        public string FilePath { get; set; }
        public string Data { get; set; }
    }

    Client:

    class Program
    {
        static void Send(NamedPipeClientStream client, Message data)
        {
            StreamString ss = new StreamString(client);
            var messageString = new JavaScriptSerializer().Serialize(data);
            Console.WriteLine("Send message: " + messageString);
            ss.WriteString(messageString);
        }
    
        static Message Receive(NamedPipeClientStream client)
        {
            StreamString ss = new StreamString(client);
            string messageString = ss.ReadString();
            Console.WriteLine("Receive message: " + messageString);
            return new JavaScriptSerializer().Deserialize<Message>(messageString);
        }
    
        static void Main(string[] args)
        {
            string filePath = "SomeFile.xml";
            var client = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut);
            try
            {
                client.Connect();
    
                var message = new Message();
                message.FilePath = filePath;
                Send(client, message);
    
                var response = Receive(client);
                var data = int.Parse(response.Data);
                data = data + 100;
    
                message = new Message();
                message.FilePath = filePath;
                message.Data = data.ToString();
                Send(client, message);
            }
            finally
            {
                client.Close();
            }
        }
    }

    StreamString:

    Die Klasse kannst du von der folgenden MSDN Seite kopieren: https://msdn.microsoft.com/de-de/library/bb546085%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    -------

    Welcher Ansatz für dich am Besten passt kann ich natürlich nur schwer sagen, da ich nicht genau weiß was das Ziel des ganzen ist.

    Ganz nebenbei: Das XML in deinem ersten Post hat kein valides Format. Um den Client und Server Code aus diesem Post zu verwenden muss das Format natürlich valide sein, da Standard XML Klassen verwendet werden.

    Quellenangaben:

    Teile des Codes und die Art der Interprozess Kommunikation sind vom Beispiel auf der folgenden MSDN Seite kopiert: https://msdn.microsoft.com/de-de/library/bb546085%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    Gruß,

    David


    Mittwoch, 30. November 2016 21:32

Alle Antworten

  • Hi,

    ich glaub der einfachste Weg ist ein Mutex zu verwenden.

    class Program
    {
        static void Main(string[] args)
        {
            var mutex = new Mutex(false, "Global\\DC9B5D68-BB56-420E-89B7-755790055769");
            try
            {
                mutex.WaitOne();
    
                // Do the file operation
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }
    }

    Aber mit dem Mutex ist nicht 100% sicher. Es funktioniert z.B. nicht wenn auch andere Applikationen, die den Mutex nicht überprüfen, die Datei gleichzeitig editieren.

    Daneben gibt es natürlich auch noch etliche andere Möglichkeiten von exclusive öffnen, über ein Process haben der die Datei Synchronisation übernimmt bis zur Verwendung von shared Memory.

    Die aufwendigere Möglichkeiten sind jedoch schwer hier als Testanwendung / Code snippet zu posten.

    Gruß,

    David   

    Dienstag, 29. November 2016 19:55
  • Die aufwendigere Möglichkeiten sind jedoch schwer hier als Testanwendung / Code snippet zu posten.

    Hallo David,

    wenn Du noch einen guten Ansatz hast, evtl. als ZIP Datei zum download?

    Danke im Voraus.

    Grüße Martin

    Mittwoch, 30. November 2016 12:42
  • Hi Martin,

    eine weitere Möglichkeit wäre eine Inter-Process  Communication.

    Eine Art wäre dass du eine Server Applikation hast die die Datei ließt und schreibt d.h. die Synchronisation übernimmt und beliebig viele Client Applikationen die den Server beauftragen die Zahl zu inkrementieren.

    -------

    Server:

    class Program
    {
        static void Send(NamedPipeClientStream client, Message data)
        {
            StreamString ss = new StreamString(client);
            var messageString = new JavaScriptSerializer().Serialize(data);
            Console.WriteLine("Send message: " + messageString);
            ss.WriteString(messageString);
        }
    
        static Message Receive(NamedPipeClientStream client)
        {
            StreamString ss = new StreamString(client);
            string messageString = ss.ReadString();
            Console.WriteLine("Receive message: " + messageString);
            return new JavaScriptSerializer().Deserialize<Message>(messageString);
        }
    
        static void Main(string[] args)
        {
            string filePath = "SomeFile.xml";
            var client = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut);
            try
            {
                client.Connect();
    
                var message = new Message();
                message.FilePath = filePath;
                Send(client, message);
    
                var response = Receive(client);
                var data = int.Parse(response.Data);
                data = data + 100;
    
                message = new Message();
                message.FilePath = filePath;
                message.Data = data.ToString();
                Send(client, message);
            }
            finally
            {
                client.Close();
            }
        }
    }

    Message:

    public class Message
    {
        public string FilePath { get; set; }
        public string Data { get; set; }
    }

    Client:

    class Program
    {
        static void Send(NamedPipeClientStream client, Message data)
        {
            StreamString ss = new StreamString(client);
            var messageString = new JavaScriptSerializer().Serialize(data);
            Console.WriteLine("Send message: " + messageString);
            ss.WriteString(messageString);
        }
    
        static Message Receive(NamedPipeClientStream client)
        {
            StreamString ss = new StreamString(client);
            string messageString = ss.ReadString();
            Console.WriteLine("Receive message: " + messageString);
            return new JavaScriptSerializer().Deserialize<Message>(messageString);
        }
    
        static void Main(string[] args)
        {
            string filePath = "SomeFile.xml";
            var client = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut);
            try
            {
                client.Connect();
    
                var message = new Message();
                message.FilePath = filePath;
                Send(client, message);
    
                var response = Receive(client);
                var data = int.Parse(response.Data);
                data = data + 100;
    
                message = new Message();
                message.FilePath = filePath;
                message.Data = data.ToString();
                Send(client, message);
            }
            finally
            {
                client.Close();
            }
        }
    }

    StreamString:

    Die Klasse kannst du von der folgenden MSDN Seite kopieren: https://msdn.microsoft.com/de-de/library/bb546085%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    -------

    Welcher Ansatz für dich am Besten passt kann ich natürlich nur schwer sagen, da ich nicht genau weiß was das Ziel des ganzen ist.

    Ganz nebenbei: Das XML in deinem ersten Post hat kein valides Format. Um den Client und Server Code aus diesem Post zu verwenden muss das Format natürlich valide sein, da Standard XML Klassen verwendet werden.

    Quellenangaben:

    Teile des Codes und die Art der Interprozess Kommunikation sind vom Beispiel auf der folgenden MSDN Seite kopiert: https://msdn.microsoft.com/de-de/library/bb546085%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    Gruß,

    David


    Mittwoch, 30. November 2016 21:32
  • Hi Martin,

    nur um es erwähnt zu haben :)

    Natürlich sind bei den Code Beispielen von mir, die ich hier poste, sehr vereinfacht.

    Bei den Post oben werden etliche mögliche Fehlquellen wie z.B. null-pointer checks, exceptions, ... einfach ignoriert.

    Interprozess Kommunikation ist kein leichtes Thema und kleine Fehler können schon zu komplizierten Deadlocks und / oder Race Conditions führen.

    Das heißt um den Code dann wirklich produktiv einsetzen zu können ist noch "etwas" Arbeit nötig :) 

    Deswegen ist auch die Methode mit dem Globalen Mutex von oben bei weitem die einfachere Variante.

    Gruß,

    David


    • Bearbeitet David Roller Mittwoch, 30. November 2016 21:44 Typo
    Mittwoch, 30. November 2016 21:43