3

我有一个应用程序,它使用 XML 文件来存储不需要在数据库中的某些数据。该文件虽然很少,但可能会同时在页面之间写入。这会产生一个问题,很可能会导致其中一个页面崩溃。我想知道是否有办法让页面渲染等到另一个完成写入文件。

我不确定我是否可以假设每个页面渲染都在自己的线程中运行;如果是这样,那么我可以像 lock() 命令一样停止该线程以等待资源可用。如果是这样,我如何在文件上实现 lock() (因为它不是内存段)?

如果它没有线程或者我不能使用 lock(),还有什么其他方法可以确保文件被写入,但是如果其他人正在使用该文件,它可以等待文件可用?

管理写入顺序和权限的方法有很多,但很简单;如果你是第二名,你会在其他人完成后写。在这一点上,我不太关心写入冲突,但并发写入是需要解决的问题。

任何帮助是极大的赞赏!

4

3 回答 3

2

编辑:运行更多测试(在单声道上),我不太确定这是最好的方法。

我没有设法使任何东西崩溃,但执行只是在 之后暂停Run()几秒钟,然后返回给调用者。所以我怀疑这不是支持这个代码片段的好兆头。

话虽如此,经过测试的场景远非现实。


另一种选择是以FileShare.ReadWrite模式打开文件,让操作系统关心锁定。

    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
于 2012-11-16T19:43:40.277 回答
1

如果它来自单台机器,您可以使用Semaphore http://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();
}

这有点像系统范围的锁。虽然不是很好,建议使用数据库。另外,其他事情可能会导致文件访问失败。您可以使用适当的锁定模式实现创建 aFileStream的东西,如果您尝试打开两个源进行写入,这将失败,但它不会执行类似lock的场景(在Monitor内部使用该类)

顺便说一句:“不需要存储在数据库中”。你问这个问题的事实表明它确实应该是。如果实施起来很麻烦,您可能需要重新考虑您的数据访问策略。带有 Code First 的实体框架之类的东西可以很容易地在数据库中“收集”东西。

于 2012-11-16T19:06:17.663 回答
-2

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

public static readonly object FileLock = new Object();

然后在您的页面中使用:

lock(YourApplicationClass.FileLock)
{
    // do stuff
}
于 2012-11-16T19:07:38.527 回答