【问题标题】:Does FileShare.None make threads wait until the filestream is closed?FileShare.None 是否让线程等到文件流关闭?
【发布时间】:2015-08-28 06:05:29
【问题描述】:

当使用文件流时,将FileShare 设置为None,并假设两个用户同时访问同一个函数想要读/写该文件。 FileShare.None 会让第二个用户请求等待还是第二个用户的请求会抛出异常?

//two users get to this this code at the same time

using (FileStream filestream = new FileStream(chosenFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
using (StreamReader sr = new StreamReader(filestream))
using (StreamWriter sw = new StreamWriter(filestream))
{
    //reading and writing to file
}

Msdn 说:无 拒绝共享当前文件。任何打开文件的请求(通过此进程或其他进程)都将失败,直到文件关闭。

但是请求会一直尝试直到文件流关闭吗?

【问题讨论】:

    标签: c# .net file thread-safety fileshare


    【解决方案1】:

    当一个进程使用FileShare.None打开一个文件进行读/写时,任何进程对该同一文件的任何后续访问都将导致Acess Denied Exception。要回答您的问题,第二个用户将获得例外。

    MSDN: FileShare.None - 拒绝共享当前文件。任何请求打开 文件(通过这个进程或另一个进程)将失败,直到文件被 关闭。


    有很多方法可以处理这类并发文件访问问题,下面的代码演示了解决这种情况的简单方法。

    //Retry 5 times when file access fails
    int retryCounter = 5;
    
    while (!isFileAccessSuccess && retryCounter > 0)
    {
        try
        {
           //Put file access logic here
    
            //If the file has been accessed successfully set the flag to true
            isFileAccessSuccess = true;
        }
        catch (Exception exception)
        {
            //Log exception
        }
        finally
        {
            //Decrease the retry count
            --retryCounter;
        }
    
        if (!isFileAccessSuccess)
        {
            //Wait sometime until initiating next try
            Thread.Sleep(10000);
        }
    }
    

    【讨论】:

    • 这个解决方案在一定程度上会起作用。但我会以某种方式更好地使用监视器/锁
    • 它会抛出IOException
    【解决方案2】:

    不,IOException 将被抛出 HResult = -2147024864Message = The process cannot access the file 'path' because it is being used by another process.

    如果要同步对文件的访问,可以使用命名等待句柄。

    public class FileAcessSynchronizer
    {
        private readonly string _path;
        private readonly EventWaitHandle _waitHandle;
    
        public FileAcessSynch(string path)
        {
            _path = path;
            _waitHandle =  new EventWaitHandle(true, EventResetMode.AutoReset, "NameOfTheWaitHandle");
        }
    
        public void DoSomething()
        {
            try
            {
                _waitHandle.WaitOne();
                using (FileStream filestream = new FileStream(chosenFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
                using (StreamReader sr = new StreamReader(filestream))
                using (StreamWriter sw = new StreamWriter(filestream))
                {
                    //reading and writing to file
                }
            }
            finally
            {
                _waitHandle.Set();
            }
        }
    }
    

    因为命名的等待句柄创建了一个critical section,所以应用程序中没有两个线程或进程(使用与等待句柄名称相同的名称)可以同时执行其中的代码。因此,一个线程或进程进入该部分,以没有人可以访问它的方式打开文件(其他应用程序),执行命令并最后离开临界区以允许您的应用程序的其他线程或进程进入临界区。

    【讨论】:

    • 而且由于 OP 指的是线程,因此值得指出的是错误消息不一定正确。无论哪个进程锁定了文件,您都会收到相同的错误消息,即使它与尝试打开文件的进程相同。
    • 像我问的问题一样,文件流的情况下能不能写这个代码实例?
    • @dotctor 该文件将被两个不同的 .net 页面以两种不同的功能访问。很抱歉我之前没有提到这一点。看起来 kurubaran 解决方案是我最好的选择。
    猜你喜欢
    • 1970-01-01
    • 2010-11-23
    • 2020-10-23
    • 1970-01-01
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-14
    相关资源
    最近更新 更多