C# 异步-停止多个任务,直到一个任务完成

C# 异步-停止多个任务,直到一个任务完成,c#,multithreading,windows-8,windows-store-apps,async-await,C#,Multithreading,Windows 8,Windows Store Apps,Async Await,我有一个应用程序,可以从服务器下载图像,如果图像尚未在本地存储,则将其存储在本地。在本例中,假设我有许多同名的图像。我只想下载一次并存储一次。 目前,我的应用程序每次被请求时都会下载它们——为了便于讨论,我向服务器发出了10个imageX.png请求。当请求返回时,应用程序正试图将其作为imageX.png存储在应用程序数据文件夹中。这就是我的问题开始的地方,因为不止一个线程试图同时写入同一个文件 这是我目前拥有的代码 public static async Task<Bitmap

我有一个应用程序,可以从服务器下载图像,如果图像尚未在本地存储,则将其存储在本地。在本例中,假设我有许多同名的图像。我只想下载一次并存储一次。 目前,我的应用程序每次被请求时都会下载它们——为了便于讨论,我向服务器发出了10个imageX.png请求。当请求返回时,应用程序正试图将其作为imageX.png存储在应用程序数据文件夹中。这就是我的问题开始的地方,因为不止一个线程试图同时写入同一个文件

这是我目前拥有的代码

    public static async Task<BitmapImage> GetBitmapImage( string folderName, string fileName )
    {
        if( await FileExists( "\\Assets\\" + folderName, fileName ) )
        {
            return new BitmapImage( new Uri( Package.Current.InstalledLocation.Path + "/Assets/" + folderName + "/" + fileName, UriKind.RelativeOrAbsolute ) );
        }
        else
        {
            // Download and save locally
            HttpClient httpClient = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage( HttpMethod.Get, "http://www.mywebsite.com/request.php?action=getImage&name=" + WebUtility.UrlEncode( fileName ) );
            HttpResponseMessage response = await httpClient.SendAsync( request, HttpCompletionOption.ResponseHeadersRead );
            BitmapImage image = new BitmapImage();
            if( response.IsSuccessStatusCode )
            {
                InMemoryRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream();
                DataWriter writer = new DataWriter( randomAccessStream.GetOutputStreamAt( 0 ) );
                writer.WriteBytes( await response.Content.ReadAsByteArrayAsync() );
                await writer.StoreAsync();

                await image.SetSourceAsync( randomAccessStream );

                var folderObj = await StorageFolder.GetFolderFromPathAsync( Package.Current.InstalledLocation.Path + "\\Assets\\" + folderName );
                var imageFile = await folderObj.CreateFileAsync( fileName, CreationCollisionOption.ReplaceExisting );
                var fs = await imageFile.OpenAsync( FileAccessMode.ReadWrite );
                writer = new DataWriter( fs.GetOutputStreamAt( 0 ) );
                writer.WriteBytes( await response.Content.ReadAsByteArrayAsync() );
                await writer.StoreAsync();
                writer.DetachStream();
                await fs.FlushAsync();
            }
            return image;
        }
    }
公共静态异步任务GetBitmapImage(字符串folderName,字符串文件名)
{
如果(等待文件存在(“\\Assets\\”+folderName,fileName))
{
返回新的位图图像(新Uri(Package.Current.InstalledLocation.Path+“/Assets/”+folderName+“/”+fileName,UriKind.RelativeOrAbsolute));
}
其他的
{
//本地下载并保存
HttpClient HttpClient=新HttpClient();
HttpRequestMessage请求=新建HttpRequestMessage(HttpMethod.Get,“http://www.mywebsite.com/request.php?action=getImage&name=“+WebUtility.UrlEncode(文件名));
HttpResponseMessage response=等待httpClient.SendAsync(请求,HttpCompletionOption.ResponseHeadersRead);
BitmapImage=新的BitmapImage();
如果(response.issucessstatuscode)
{
InMemoryRandomAccessStream randomAccessStream=新建InMemoryRandomAccessStream();
DataWriter writer=新的DataWriter(randomAccessStream.GetOutputStreamAt(0));
WriteBytes(wait response.Content.ReadAsByteArrayAsync());
等待writer.StoreAsync();
wait image.SetSourceAsync(随机访问流);
var folderObj=await-StorageFolder.GetFolderFromPathAsync(Package.Current.InstalledLocation.Path+“\\Assets\\”+folderName);
var imageFile=await folderObj.CreateFileAsync(文件名,CreationCollisionOption.ReplaceExisting);
var fs=await imageFile.OpenAsync(FileAccessMode.ReadWrite);
writer=newdatawriter(fs.GetOutputStreamAt(0));
WriteBytes(wait response.Content.ReadAsByteArrayAsync());
等待writer.StoreAsync();
writer.DetachStream();
等待fs.FlushAsync();
}
返回图像;
}
}
我想我需要的是在“if FileExists”之前暂停线程,直到前一个线程完成其任务并在必要时保存到磁盘。其余线程将在FileExists调用中立即返回true
有人能给我指出正确的方向吗?

假设您有10个任务正在运行(每个任务下载一个不同的图像),并且您希望在每个任务完成后按顺序处理:

Task[] tasks = //...

while(tasks.Length != 0) {

    int index = Task.WaitAny(taks);
    var completedTask = tasks[index];
    var image = completedTask.Result;

    //save to file

    var tasksList = tasks.ToList();
    tasksList.RemoveAt(index);
    tasks = tasksList.ToArray();

}
我想我需要的是在“if FileExists”之前暂停线程,直到前一个线程完成其任务并在必要时保存到磁盘

如果您想这样做,可以使用
信号量lim
作为一种
异步
兼容锁,例如:

await semaphore.WaitAsync();
try
{
  if (await FileExists(...))
  ...
}
finally
{
  semaphore.Release();
}

但是,这将限制您每次只能下载一次。

什么是
RemoteAt
?我认为这可能是
RemoveAt
的输入错误,但这仍然没有意义,因为
RemoveAt
不会返回任何内容。