代码之家  ›  专栏  ›  技术社区  ›  Rob Cooper

多线程环境中的文件访问策略(Web应用程序)

  •  6
  • Rob Cooper  · 技术社区  · 17 年前

    我有一个文件,它是一些数据的XML表示,这些数据是从Web服务获取的,并在Web应用程序中本地缓存的。我们的想法是 非常 静态,但只是 可以 改变。所以我将它设置为缓存到一个文件,并在文件上粘贴一个监视器来检查它是否已被删除。一旦删除,文件将从其源刷新并重新生成。

    不过,我现在遇到了一些问题,因为很明显,在多线程环境中,当数据还在读/写文件时,它会在尝试访问数据时崩溃。

    这让我很困惑,因为我添加了一个要锁定的对象,并且在读/写过程中总是锁定这个对象。据我所知,从其他线程尝试访问会被告知“等待”直到释放锁?

    只是想让你知道,我对多线程开发非常陌生,所以我完全愿意接受这是我的一个失误:)

    • 我错过什么了吗?
    • 在多线程环境中,最好的文件访问策略是什么?

    编辑

    对不起-我应该说这是用 ASP.NET 2 :)

    5 回复  |  直到 10 年前
        1
  •  6
  •   Eric Z Beard    17 年前

    这是我用来确保文件不被其他进程锁定的代码。这不是100%的万无一失,但大部分时间都能完成工作:

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

    显然,您可以调整超时和重试以适应您的应用程序。我使用它来处理需要一段时间才能写入的巨大ftp文件。

        2
  •  1
  •   Ubiguchi    17 年前

    如果锁定的对象存储为 静止的 然后,锁应该适用于同一应用程序域中的所有线程,但也许您需要上载一个代码示例,以便我们可以查看有问题的行。

    也就是说,一种想法是检查IIS是否配置为运行在 Web Garden 模式(即执行应用程序的多个进程),它会破坏锁定逻辑。虽然您可以使用互斥修复这种情况,但重新配置应用程序以在单个进程中执行会更容易,但在处理Web花园设置之前和之后检查性能是明智的,因为这可能会影响性能。

        3
  •  1
  •   Antti Kurenniemi    17 年前

    您可以用一个临时名称(“data.xml_tmp”)创建文件,当它准备好后,将名称改为它应该是的名称。这样,在它准备就绪之前,没有其他进程可以访问它。

        4
  •  1
  •   Community Mohan Dere    8 年前

    好吧,我一直在研究这个问题,最后创建了一个压力测试模块,基本上从几个线程中敲出我的代码中的垃圾。( See Related Question )

    从这一点开始,在我的代码中找到漏洞要容易得多。事实证明,我的代码实际上并不遥远,但它可以进入一条逻辑路径,这条路径基本上导致读/写操作堆叠起来,这意味着如果没有及时清除它们,它将迅速发展!

    一旦我把它拿出来,再做一次压力测试,一切都很好!

    所以,我什么都没做 特殊的 在我的文件访问代码中,只是确保我使用 lock 适当时的陈述(即读写时)。

        5
  •  0
  •   gmail user    10 年前

    如何使用 AutoResetEvent 在线程之间通信?我创建了一个控制台应用程序,它在 createfile 方法,然后将该文件复制到 main 方法

     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();
        }
    
    推荐文章