Domanda

Ho un file che è una rappresentazione XML di alcuni dati presi da un servizio Web e memorizzati nella cache locale all'interno di un'applicazione Web.L'idea è che questi dati lo siano molto statico, ma giusto Potrebbe modifica.Quindi l'ho impostato per memorizzare nella cache un file e ho bloccato un monitor per verificare se è stato eliminato.Una volta eliminato, il file verrà aggiornato dalla sua origine e ricostruito.

Ora però sto riscontrando problemi, perché ovviamente in un ambiente multi-thread cade mentre tenta di accedere ai dati mentre sta ancora leggendo/scrivendo il file.

Questo mi confonde, perché ho aggiunto un oggetto su cui bloccarmi e questo è sempre bloccato durante la lettura/scrittura.Avevo capito che ai tentativi di accesso da altri thread sarebbe stato detto di "attendere" fino al rilascio del blocco?

Giusto per farti sapere, sono davvero nuovo nello sviluppo multi-thread, quindi sono totalmente disposto ad accettare che questo sia un errore da parte mia :)

  • Mi sto perdendo qualcosa?
  • Qual è la migliore strategia di accesso ai file in un ambiente multi-thread?

Modificare

Scusa, avrei dovuto dire che questo sta usando ASP.NET 2.0 :)

È stato utile?

Soluzione

Ecco il codice che utilizzo per assicurarmi che un file non sia bloccato da un altro processo.Non è infallibile al 100%, ma nella maggior parte dei casi fa il suo lavoro:

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

Ovviamente è possibile modificare i timeout e i tentativi per adattarli alla propria applicazione.Lo uso per elaborare file FTP di grandi dimensioni che richiedono molto tempo per essere scritti.

Altri suggerimenti

Se stai bloccando un oggetto archiviato come file statico quindi il blocco dovrebbe funzionare per tutti i thread nello stesso dominio dell'applicazione, ma forse è necessario caricare un esempio di codice in modo che possiamo dare un'occhiata alle righe incriminate.

Detto questo, si potrebbe verificare se IIS è configurato per l'esecuzione Giardino Web modalità (es.più di 1 processo che esegue l'applicazione) che interromperebbe la logica di blocco.Anche se potresti risolvere una situazione del genere con un mutex, sarebbe più semplice riconfigurare la tua applicazione per l'esecuzione in un unico processo, anche se sarebbe saggio controllare le prestazioni prima e dopo aver modificato le impostazioni del web garden poiché potrebbe potenzialmente influire prestazione.

Potresti forse creare il file con un nome temporaneo ("data.xml_TMP") e, quando è pronto, cambiare il nome in quello che dovrebbe essere.In questo modo, nessun altro processo potrà accedervi prima che sia pronto.

OK, ci ho lavorato e ho finito per creare un modulo di stress test per eliminare praticamente ogni schifezza dal mio codice da diversi thread (Vedi la domanda correlata).

Da questo momento in poi è stato molto più facile trovare buchi nel mio codice.Si scopre che il mio codice non era in realtà lontano, ma c'era un certo percorso logico in cui poteva entrare e che sostanzialmente causava l'accumulo delle operazioni di lettura/scrittura, il che significa che se non venivano cancellate in tempo, sarebbe vai bum!

Una volta estratto il dispositivo, ho eseguito nuovamente lo stress test e tutto ha funzionato bene!

Quindi non ho fatto veramente nulla speciale nel mio codice di accesso al file, mi sono solo assicurato di averlo usato lock dichiarazioni ove opportuno (ad es.durante la lettura o la scrittura).

Che ne dici di usare AutoResetEvent comunicare tra i thread?Ho creato un'app console che crea un file di circa 8 GB createfile metodo e quindi copiare il file main metodo

 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();
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top