Frage

Ich habe eine Datei, die eine XML-Darstellung einiger Daten ist, die von einem Webdienst übernommen und lokal in einer Webanwendung zwischengespeichert werden.Die Idee dahinter ist, dass diese Daten vorhanden sind sehr statisch, aber einfach könnte ändern.Deshalb habe ich es so eingerichtet, dass es in einer Datei zwischengespeichert wird, und einen Monitor dagegen angebracht, um zu überprüfen, ob es gelöscht wurde.Nach dem Löschen wird die Datei aus ihrer Quelle aktualisiert und neu erstellt.

Allerdings stoße ich jetzt auf Probleme, da es in einer Multithread-Umgebung offensichtlich abstürzt, da es versucht, auf die Daten zuzugreifen, während es noch die Datei liest/schreibt.

Das verwirrt mich, weil ich ein Objekt zum Sperren hinzugefügt habe und dieses beim Lesen/Schreiben immer gesperrt ist.Nach meinem Verständnis würde versuchter Zugriff von anderen Threads aus angewiesen werden, zu „warten“, bis die Sperre aufgehoben wird?

Nur um Sie wissen zu lassen, ich bin ein echter Neuling in der Multithread-Entwicklung und bin daher durchaus bereit zu akzeptieren, dass dies ein Fehler meinerseits ist :)

  • Vermisse ich etwas?
  • Was ist die beste Dateizugriffsstrategie in einer Multithread-Umgebung?

Bearbeiten

Tut mir leid, ich hätte sagen sollen, dass das nutzlos ist ASP.NET 2.0 :)

War es hilfreich?

Lösung

Hier ist der Code, den ich verwende, um sicherzustellen, dass eine Datei nicht durch einen anderen Prozess gesperrt wird.Es ist nicht 100 % narrensicher, aber es erledigt die meiste Zeit seine Arbeit:

    /// <summary>
    /// Blocks until the file is not locked any more.
    /// </summary>
    /// <param name="fullPath"></param>
    bool WaitForFile(string fullPath)
    {
        int numTries = 0;
        while (true)
        {
            ++numTries;
            try
            {
                // Attempt to open the file exclusively.
                using (FileStream fs = new FileStream(fullPath,
                    FileMode.Open, FileAccess.ReadWrite, 
                    FileShare.None, 100))
                {
                    fs.ReadByte();

                    // If we got this far the file is ready
                    break;
                }
            }
            catch (Exception ex)
            {
                Log.LogWarning(
                   "WaitForFile {0} failed to get an exclusive lock: {1}", 
                    fullPath, ex.ToString());

                if (numTries > 10)
                {
                    Log.LogWarning(
                        "WaitForFile {0} giving up after 10 tries", 
                        fullPath);
                    return false;
                }

                // Wait for the lock to be released
                System.Threading.Thread.Sleep(500);
            }
        }

        Log.LogTrace("WaitForFile {0} returning true after {1} tries",
            fullPath, numTries);
        return true;
    }

Natürlich können Sie die Zeitüberschreitungen und Wiederholungsversuche an Ihre Anwendung anpassen.Ich verwende dies, um große FTP-Dateien zu verarbeiten, deren Schreiben eine Weile dauert.

Andere Tipps

Wenn Sie ein Objekt sperren, das als gespeichert ist statisch Dann sollte die Sperre für alle Threads in derselben Anwendungsdomäne funktionieren. Möglicherweise müssen Sie jedoch ein Codebeispiel hochladen, damit wir uns die fehlerhaften Zeilen ansehen können.

Ein Gedanke wäre jedoch, zu prüfen, ob IIS für die Ausführung konfiguriert ist Webgarten Modus (d. h.mehr als ein Prozess, der Ihre Anwendung ausführt), was Ihre Sperrlogik zerstören würde.Während Sie eine solche Situation mit einem Mutex beheben könnten, wäre es einfacher, Ihre Anwendung so neu zu konfigurieren, dass sie in einem einzigen Prozess ausgeführt wird. Allerdings wäre es ratsam, die Leistung vor und nach der Manipulation der Webgarten-Einstellungen zu überprüfen, da dies möglicherweise Auswirkungen haben kann Leistung.

Sie könnten die Datei möglicherweise mit einem temporären Namen („data.xml_TMP“) erstellen und, wenn sie fertig ist, den Namen in den gewünschten Namen ändern.Auf diese Weise greift kein anderer Prozess darauf zu, bevor es fertig ist.

OK, ich habe daran gearbeitet und am Ende ein Stresstest-Modul erstellt, um im Grunde den Mist aus mehreren Threads aus meinem Code herauszuhämmern (Siehe verwandte Frage).

Ab diesem Zeitpunkt war es viel einfacher, Lücken in meinem Code zu finden.Es stellte sich heraus, dass mein Code nicht wirklich weit weg war, aber es gab einen bestimmten logischen Pfad, in den er eintreten konnte, was im Grunde dazu führte, dass sich Lese-/Schreibvorgänge stapelten, was bedeutete, dass dies der Fall wäre, wenn sie nicht rechtzeitig gelöscht würden geh bumm!

Nachdem ich das herausgenommen und meinen Stresstest erneut durchgeführt hatte, funktionierte alles einwandfrei!

Also habe ich eigentlich nichts gemacht besonders in meinem Dateizugriffscode habe ich nur sichergestellt, dass ich ihn verwendet habe lock gegebenenfalls Aussagen (d. h.beim Lesen oder Schreiben).

Wie wäre es mit der Verwendung AutoResetEvent zwischen Threads kommunizieren?Ich habe eine Konsolen-App erstellt, die eine Datei mit etwa 8 GB erstellt createfile Methode und kopieren Sie dann diese Datei hinein main Methode

 static AutoResetEvent waitHandle = new AutoResetEvent(false);
    static string filePath=@"C:\Temp\test.txt";
    static string fileCopyPath=@"C:\Temp\test-copy.txt";
    static void Main(string[] args)
    {
        Console.WriteLine("in main method");
        Console.WriteLine();
        Thread thread = new Thread(createFile);
        thread.Start();

        Console.WriteLine("waiting for file to be processed ");
        Console.WriteLine();
        waitHandle.WaitOne();
        Console.WriteLine();

        File.Copy(filePath, fileCopyPath);
        Console.WriteLine("file copied ");

    }


    static void createFile()
    {

        FileStream fs= File.Create(filePath);            
        Console.WriteLine("start processing a file "+DateTime.Now);
        Console.WriteLine();
        using (StreamWriter sw = new StreamWriter(fs))
        {
            for (long i = 0; i < 300000000; i++)
            {
                sw.WriteLine("The value of i is " + i);

            }
        }
        Console.WriteLine("file processed " + DateTime.Now);
        Console.WriteLine();

        waitHandle.Set();
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top