1

我需要能够读取应该保存在本地的文件,如果该文件不存在,我需要下载它。这是我要完成的简化版本:

// See if the file exists locally
if (!File.Exists(physicalPath))
{
    // file doesn't exist, download it
    using (WebClient client = new WebClient())
    {
        client.DownloadFile(url, physicalPath);
    }
}

// open up the file and do stuff ..

由于后来发生的事情,我无法使用 Streams,但我需要先将文件保存到磁盘。

一次调用一切都很好,但是您可以想象,当 1,000 个进程同时通过此函数运行时会出现问题。以下是我认为当两个进程同时启动时会发生的情况:

过程1:

  1. 该文件是否存在于本地?不
  2. 开始下载文件
  3. 下载文件完成
  4. 读取文件

过程2:

  1. 该文件在本地是否存在?是的
  2. 读取文件
  3. 例外!!!文件正被另一个进程使用

所以进程 2 会看到文件存在,但这只是因为进程 1 已经在主动下载文件,而进程 1 还没有完成文件下载。我希望进程 2(以及所有其他进程正在进行)是等待进程 1 完成下载文件。

在这里帮助我们的是,无论进程 1 下载什么都适用于进程 2,这意味着进程 2 不会有不同的数据,也不需要写入文件。如果进程 1 正在下载文件,则进程 2 最好不必下载文件,它可以等待进程 1 完成。

综上所述,如果进程 1 已经在下载其他进程所需的文件,我怎样才能阻止其他进程继续,以便他们等待进程 1 完成?文件准备好后,如何让进程 2 继续?(使用 C# 4.0)

我还应该澄清一下,这个操作的速度是优先级#1。

4

2 回答 2

2

整个设置听起来有点容易出现难以缓和的竞争条件。

我会创建一个单独的(单例)进程,负责将请求排队并为其他进程下载它们。您可以通过某种 IPC(如 WCF)与它交谈。

于 2013-04-26T14:48:34.657 回答
0

只需使用互斥锁来同步进程。这样的事情应该可以解决问题:

public static class FileRepository
{
    public static FileInfo GetFile(string fileName)
    {
        FileInfo MyFile;

        if(!File.Exists(fileName))
        {
            // Use some unique name + filename as Mutex Name
            using(new Mutex(true, fileName))
            {
                // Will block if another Process already downloads the file
                if(Mutex.WaitOne())
                {
                    // Download the File and safe FileInfo in MyFile
                    // ...
                }
            }
        }
        else
        {
            MyFile = new FileInfo(fileName);
        }       

        return MyFile;
    }
}
于 2013-04-26T14:58:27.360 回答