2012-11-16 52 views
3

我有一個應用程序使用XML文件來存儲某些不需要在數據庫中的數據。這個文件雖然很少,但可能會同時寫入頁面之間。這造成了一個問題,很可能導致其中一個頁面崩潰。我想知道是否有一種方法可以讓頁面呈現等到另一個寫入文件。鎖定(文件)在頁面之間寫入?

我不確定是否可以假設每個頁面渲染都在其自己的線程中運行;如果是這樣,那麼我可以像lock()命令那樣暫停該線程以等待資源可用。如果是這樣,我怎麼能在文件上實現一個鎖()(因爲它不是一個內存段)?

如果它不是線程的或者我不能使用lock(),還有其他什麼方法來確保文件被寫入,但是如果其他人使用該文件,它可以等待文件可用?

有很多管理寫入順序和權限的方法,但對此很簡單;如果你排在第二位,那麼在另一個人完成後你會寫入。在這一點上,我不太關心寫碰撞,但是併發寫作是需要解決的問題。

任何幫助,非常感謝!

+1

還是應該將其存儲在數據庫中。這將解決併發問題,並在出現問題時保持原子化。 –

+0

我建議你使用數據庫,並根據你的需要實現'樂觀'或'悲觀'併發。 – RAS

+0

你爲什麼會認爲會'崩潰'?請詳細說明。不要解決你沒有的問題。 – avishayp

回答

1

如果一臺機器上的,你可以使用一個Semaphorehttp://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx

private static Semaphore _fileSemaphore = new Semaphore(1, 1, "myFileGlobalSemaphore"); 

// later... 

try 
{ 
    _fileSemaphore.WaitOne(); 
    // do stuff.. 
} 
finally 
{ 
    _fileSemaphore.Release(); 
} 

這有點像一個全系統的鎖。不是很好,但會建議一個數據庫。另外,其他的事情可能會導致文件訪問失敗。您可以執行一些操作,創建一個FileStream的適當鎖定模式,如果您嘗試打開兩個來源的書寫,但它不會執行類似lock的場景(其在內部使用Monitor類)

Btw:「不需要存儲在數據庫中」。你問這個問題的事實表明它確實應該是。如果實施起來很痛苦,您可能需要重新考慮您的數據訪問策略。類似Entity Framework和Code First的東西可以很容易地在數據庫中「查找」東西。

+0

這實際上取決於實施。其中很多都與可用性有關,而短的應用程序設置可以保存在文件中。它減少了對數據庫的命中數量,並且如果應用程序需要在另一個系統上覆制,那麼它就不那麼重要。 –

-2

使用一些全局鎖定對象。例如添加到您的global.asax.cs:

public static readonly object FileLock = new Object(); 
在頁面

然後使用:

lock(YourApplicationClass.FileLock) 
{ 
    // do stuff 
} 
+1

注意,這隻適用於你只有一個AppDomain(即只有一個工作進程) –

+0

另外:他說他不能保證每個訪問都在自己的線程中運行。如果你試圖在同一個線程上鎖定同一個對象,它不會阻止你 –

+0

我的意思是,我對ASPX應用程序池不夠熟悉,以確定是否實際上每個頁面都被執行它自己的線程。我試圖用Google搜索它沒有任何結果。 –

2

編輯:運行一些測試(單聲道),我不是很確定這是最好的方法。

我沒有設法使任何事情崩潰,但執行只是在Run()之後暫停幾秒鐘,然後再回到調用方。所以我懷疑這不是代碼片斷的好兆頭。

這就是說,測試的情況是不切實際的。


另一種選擇是在FileShare.ReadWrite模式打開的文件,並讓OS關心lockings。

public void Run() 
    { 
     var file = @"/home/me/test.txt"; 
     var threads = new Thread[3]; 

     for (int i = 0; i < threads.Length; i++) { 
      int j = i; 
      threads[j] = new Thread(s => { 
      Console.WriteLine("thread " + j + " is running..."); 
      using (var stream = File.Open(file, FileMode.OpenOrCreate, 
        FileAccess.ReadWrite, FileShare.ReadWrite)) 
      { 
       Console.WriteLine("thread " + j + " is holding the file!"); 
       var data = ASCIIEncoding.ASCII.GetBytes("hello, I'm stream " + j); 
       stream.Write(data, 0, data.Length); 
       Thread.Sleep(1000); 
      }});  
     } 

     foreach (var t in threads) 
      t.Start(); 

     foreach (var t in threads) 
      t.Join(); 

     Console.WriteLine(File.ReadAllText(file)); 
    } 

輸出:

thread 1 is running... 
thread 0 is running... 
thread 2 is running... 
thread 2 is holding the file! 
thread 1 is holding the file! 
thread 0 is holding the file! 
hello, I'm stream 0