kostenloser Webspace werbefrei: lima-city


Mit C# Ordner sperren?

lima-cityForumProgrammiersprachenProgrammieren mit .NET & Mono

  1. Autor dieses Themas

    faultier89

    faultier89 hat kostenlosen Webspace.

    Hi

    Ich habe gerade ein Projekt wieder angefangen, welches ich ein paar Wochen/Monate auf Eis liegen hatte. Zur Zeit habe ich da folgendes Problem:

    Ein Ordner stellt sozusagen eine Aufgabe dar. Er beinhaltet ein paar config-Datein und ein einige Binärdateien. Ein Programm durchsucht einen bestimmten Ordner regelmäßig nach solchen Aufgabenordnern.

    Das Anlegen von neuen Aufgaben kann natürlich etwas dauern. Damit das Programm nicht mit unfertigen Aufgaben anfängt, muss ich den Ordner irgendwie sperren.

    Habt ihr dafür irgend welche Vorschläge wie man das am Sinnvollsten lösen kann?

    Gruß
  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. Hallo faultier89,

    ich habe Dir noch mal den alten Thread rausgesucht (er steht ja noch auf der ersten Seite :wink: und ich bin zu faul das ganze nochmal zu schreiben):
    http://www.lima-city.de/thread/c-ein-grosses-oder-mehrere-kleine-programme
  4. heroes-of-legends

    heroes-of-legends hat kostenlosen Webspace.

    Je nach dem, falls er die Ordner nicht programmatisch sondern manuell anlegt löst es das problem allerdings nicht.

    Die Lösung wäre ein FlagFile im Ordner zu erstellen welches dem Programm signalisiert das der Ordner vollständig ist.

    Falls du die Ordner doch programmatisch mit einem anderem Programm erstellst will ich an dieser Stelle mal den Begriff "Mutex" in den Raum werfen. Hierbei handelt es sich um einen systemweiten Lock, dieser lässt sich (im gegensatz zu Locks, welche es in .NET auch unter dem schlüsselwort "lock" gibt) auf einen String setzen.
  5. Autor dieses Themas

    faultier89

    faultier89 hat kostenlosen Webspace.

    Hi

    Danke nochmal für die Infos.

    Ich werde neue Ordner wohl auch aus dem Programm heraus erstellen, weshalb eine einfache Verwaltungsklasse ausreichen sollte. Meine Idee war jetzt eine statische Klasse zu erstellen mit einer Liste aus structs welche Infos über die Ordner enthalten.

    struct Lock
        {
            public String path;
            public LockType type;
            public int count;
    
            public Lock(String path, LockType type)
            {
                this.path = path;
                this.type = type;
                count = 1;
            }
    
            public void inc()
            {
                count++;
            }
    
            public void dec()
            {
                count--;
            }
        }



    static class Locker
        {
            private static List<Lock> locked = new List<Lock>();
    
            public static void block(String path, LockType type)
            {
                lock(locked)
                {
                    int i = findLock(path);
                    if (i  >= 0)
                    {
                        locked[i].inc();
                    }
                    else
                    {
                        locked.Add(new Lock(path, type));
                    }
                }
            }
    
            private static int findLock(String path)
            {
                for (int i = 0; i < locked.Count; i++)
                {
                    if (path.Equals(locked[i].path))
                        return i;
                }
    
                return -1;
            }
    
    ...


    Der LockType gibt an, welche Art von Zugriff zur Zeit auf den Ordner stattfindet. Bei bestimmten Zugriffsarten können nämlich mehrere Threads drauf zugreifen ohne sich im Weg zu stehen. Der count ist dafür da, damit ich weiß wann der letzte Thread mit seiner Aufgabe fertig ist. Der LockType wird zur Zeit noch nicht berücksichtigt.

    Mein Problem ist jetzt, dass es mit dem Zähler irgendwelche Probleme gibt. Beim Debuggen sieht man, dass der beim zweiten Lock die inc-Funktion aufruft und count danach auch auf 2 ist. Beim dritten Lock ist count allerdings vor dem inc() wieder auf 1 gesetzt worden.

    Die Locks rufe ich zum Testen manuell per Button auf. Die dec-Funktion oder der Konstruktor werden an keiner Stelle aufgerufen. (Habe bei beiden nen BreakPoint drin, wo der nicht reinspringt.)

    Jemand ne Idee?

    Gruß
  6. Hallo faultier89,

    ich habe die Sache bei mir mit fogendem Code nachgestellt:
    using System;
    using System.Collections.Generic;
    using System.Threading;
    
    namespace Test
    {
        class Lock
        {
            public int count = 0;
    		
            public void inc()
            {
                count++;
            }
    		
            public void dec()
            {
                count--;
            }
    		
        }
    	
        class Program
        {	
            static List<Lock> locked;
    		
            static void worker()
            {
                lock(locked)
                {
                    locked[0].inc();
    		Console.WriteLine(locked[0].count);
                }
    			
                Thread.Sleep(400);
    			
                lock(locked)
                {
                    locked[0].dec();
                    Console.WriteLine(locked[0].count);
                }
            }
    		
            public static void Main(string[] args)
            {
                locked = new List<Lock>();
                locked.Add(new Lock());
    			
                for(int i = 0;i<20;i++)
                {
                    Thread thread = new Thread(worker);
                    thread.Start();
                    Thread.Sleep(50);
                }
    			
                Thread.Sleep(500);
    						
                Console.Write("Press any key to continue . . . ");
                Console.ReadKey(true);
            }
        }
    }
    Allerdings funktioniert das bei mir einwandfrei. Von daher vermute ich, dass das Problem zumindest nicht in dem von Dir geposteten Code liegt.
  7. Autor dieses Themas

    faultier89

    faultier89 hat kostenlosen Webspace.

    Hatte das Problem schon gefunden. das "Lock" wei bei mir nen struct. Und nen struct ist nen Wertetyp. Da wird also immer ne Kopie übergeben. Der incrementiert also ne Kopie von der struct in der Liste und lässt die eigentliche struct in der Liste unberührt. Mit ner Class, welche ja in der Regel als Verweis übergeben wird funzt das alles wunderbar. :-)

    Bleibt für mich dann nur noch die Frage, wofür zum Geier sind structs denn dann überhaupt noch gut? -.-
  8. heroes-of-legends

    heroes-of-legends hat kostenlosen Webspace.

    du kannst auch per "ref" definieren das ein methodenparameter als referenz übergeben werden soll. somit kannst du dein struct behalten.

    Beispiel:
    class Program
        {
            public static void Increment(ref MyStruct myStruct)
            {
                myStruct.value++;
            }
    
            static void Main(string[] args)
            {
                MyStruct myStruct = new MyStruct();
                myStruct.value = 5;
                Console.WriteLine(myStruct.value.ToString());
                Increment(ref myStruct);
                Console.WriteLine(myStruct.value.ToString());
                Console.ReadKey(true);
            }
        }
    
    
        public struct MyStruct
        {
            public int value;
        }


    Ausgabe:
    5
    6


    Außerdem solltest du den Lock nicht auf die Liste setzen auf der du arbeitest. Du solltest dir ein zusätzliches SyncObjekt anlegen.

    Ich habe mir mal erlaubt dein Verwaltungsklasse etwas zu optimieren.

    IOLock Struct - Speichert vorhandene Locks
    struct IOLock
        {
            public FileSystemInfo Path;
            public LockType LockType;
        }


    LockType Enumeration - Gibt den LockType an.
    public enum LockType
        {
            Read,
            ReadWrite
        }


    IOLocker Klasse - Stellt methoden zur Threadsicheren Synchronisation von Dateioperationen bereit.
    public static class IOLocker
        {
            public delegate object DefaultMethodInvoker(params object[] args);
    
            private static Dictionary<Guid, IOLock> locks = new Dictionary<Guid, IOLock>();
            private static object operationSyncLock = new object();
    
            public static object Lock(FileSystemInfo path, LockType lockType, Delegate codeToRun, params object[] args)
            {
                if (path == null)
                    throw new ArgumentNullException("path");
    
                if (codeToRun == null)
                    throw new ArgumentNullException("codeToRun");
    
                if (codeToRun.Method.GetParameters().Count() != args.Length)
                    throw new ArgumentException("The count of parameters is different from the expected count.");
    
                Guid lockId = Guid.Empty;
                try
                {
                    lockId = SetLock(path, lockType);
                    
                    return codeToRun.DynamicInvoke(args);
                }
                finally
                {
                    ReleaseLock(lockId);
                }
            }
    
            private static Guid SetLock(FileSystemInfo path, LockType lockType)
            {
                lock (operationSyncLock)
                {
                    while (!checkLock(path, lockType))
                        System.Threading.Thread.Sleep(50); //Schlafen wärend Pfad gesperrt ist.
    
                    var lockId = Guid.NewGuid();
                    locks.Add(lockId, new IOLock() { Path = path, LockType = lockType });
                    return lockId;
                }
            }
    
            private static void ReleaseLock(Guid id)
            {
                locks.Remove(id);
            }
    
            private static bool checkLock(FileSystemInfo path, LockType lockType)
            {
                //Alle Locks wählen welche auf den selben Pfad zielen.
                var locksQuery = from l in locks
                                 where string.Compare(l.Value.Path.FullName, path.FullName, true) == 0
                                 select l;
                if (locksQuery.Count() == 0) //Wenn keine Locks für diesen Pfad gesetzt sind => Lock erlauben.
                    return true;
    
                //Ab hier mind. 1 Lock für diesen Pfad.
    
                if (lockType  == LockType.ReadWrite) //Wenn Schreiblock erforderlich => Lock ablehnen.
                    return false;
    
                if (locksQuery.Count() == 1 &&
                    (locksQuery.First().Value.LockType == LockType.ReadWrite)) //Wenn exakt ein Lock existiert, welcher Schreiblock hat => Lock ablehnen
                    return false;
    
                return true; //Lock erlauben.
            }
        }


    FileSystemInfo = Basisklasse von FileInfo und DirectoryInfo

    Code ist getestet und funktioniert.
    Viel Spaß damit :) hatte gerade bisschen lange weile.

    grüße
    Doomdrake

    Beitrag zuletzt geändert: 7.6.2011 14:28:39 von heroes-of-legends
  9. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!