简体   繁体   English

下载c#中段的文件时发生死锁

[英]Deadlock occurs in downloading files with segments in c#

I'm trying to find why sometimes deadlock happens when downloading a file by splitting into multiple segments.我试图通过拆分为多个段来找出为什么有时会在下载文件时发生死锁。 I'm using async/await, but this doesn't work every time.我正在使用 async/await,但这并不是每次都有效。 Any ideas on how can i identify the problem?关于如何识别问题的任何想法?

 IEnumerable<Task<bool>> downloadTasksQuery = from segment in job.Segments select RunSegment(segment);
 Task<bool>[] downloadTasks = downloadTasksQuery.ToArray();
 bool[] lengths = await Task.WhenAll(downloadTasks).ConfigureAwait(false);

after the await many times doesn't come back.经过多次等待后不会回来。

And the RunSegment() method和 RunSegment() 方法

Method to download the segment using http client.使用 http 客户端下载片段的方法。

        private async Task<bool> RunSegment(DownloadSegment segment)
        {
            try
            {
                int TotalBytesReadedInSession=0;
                if (segment.LocalStream == null) return false;
                segment.Status = DownloadStatus.Starting;
                segment.IsBusy = true;
                segment.Error = string.Empty;
                segment.Speed = 0;
                var request = new HttpRequestMessage(HttpMethod.Get, job.Url);
                request.Headers.Range = new RangeHeaderValue(segment.Start + segment.BytesDownloaded, segment.End);
                var response = await job.DownloadManager.httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationTokenSource.Token);
                response.EnsureSuccessStatusCode();
                using (var stream = await response.Content.ReadAsStreamAsync())
                {
                    DateTime dtInitial = DateTime.Now;
                    var buffer = new byte[job.DownloadManager.bufferSize];
                    var isMoreDataToRead = true;
                    segment.Status = DownloadStatus.Downloading;
                    segment.IsBusy = true;
                    job.Status = DownloadStatus.Downloading;
                    do
                    {
                        try
                        {
                            cancellationTokenSource.Token.ThrowIfCancellationRequested();
                            var read = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationTokenSource.Token);
                            TotalBytesReadedInSession += read;
                            if((DateTime.Now - dtInitial).TotalSeconds >= 1)
                            {
                                segment.Speed = TotalBytesReadedInSession / (DateTime.Now-dtInitial).TotalSeconds;
                            }
                            if (read == 0 || (segment.End - (segment.Start + segment.BytesDownloaded)) <= 0)
                            {
                                isMoreDataToRead = false;
                                if ((segment.End - (segment.Start + segment.BytesDownloaded)) <= 0)
                                {
                                    segment.BytesDownloaded = (segment.End - segment.Start);
                                    segment.Status = DownloadStatus.Completed;
                                    segment.IsBusy = false;
                                }
                                return true;
                            }
                            else
                            {
                                // Write data on disk.
                                if (segment.End > 0 && (segment.Start + segment.BytesDownloaded + read) > segment.End)
                                {
                                    // adjust the 'readSize' to write only necessary bytes
                                    read = Convert.ToInt32((segment.End - segment.Start - segment.BytesDownloaded));
                                }
                                if (read > 0)
                                {
                                    lock (segment.LocalStream)
                                    {
                                        segment.LocalStream.Seek(segment.Start + segment.BytesDownloaded, SeekOrigin.Begin);
                                    }
                                    await segment.LocalStream.WriteAsync(buffer, 0, read);

                                    segment.BytesDownloaded += read;
                                    segment.Progress = ((segment.BytesDownloaded) * 1d) / ((segment.End - segment.Start) * 1d) * 100;
                                }
                                else if ((segment.Start + segment.BytesDownloaded) >= segment.End) { segment.IsBusy = false; segment.Status = DownloadStatus.Completed; return true; }
                            }
                        }
                        catch (Exception ex)
                        {
                            segment.Speed = 0;
                            if (ex is OperationCanceledException)
                            {
                                segment.Error = string.Empty;
                                segment.Status = DownloadStatus.Stopped;
                                segment.IsBusy = false;
                                return false;
                            }
                            segment.CurrentTryError = +1;
                            segment.Status = DownloadStatus.Error;
                            segment.Error = ex.Message;
                            if (stream != null) { stream.Close(); stream.Dispose(); }
                            await Task.Delay(3000);
                            if ((segment.CurrentTryError - 1) > job.DownloadManager.MaximumTryErrorCounts) { segment.IsBusy = false; return false; }
                            return await RunSegment(segment).ConfigureAwait(false);
                        }
                    } while (isMoreDataToRead);
                }
            }           
        catch (Exception ex)
            {
                segment.Speed = 0;
                segment.Status = DownloadStatus.Error;
                segment.Error = ex.Message;
                segment.IsBusy = false;
                return false;
            }
            return true;
        }

could it be because the filestream?可能是因为文件流? I create a file stream before downloading.我在下载之前创建了一个文件 stream 。 all segments are writed in same file所有段都写在同一个文件中

I would guess actually that this entire section should be locked at the file level (where multiple segments are not writing at the same time) and you might be okay.实际上我猜想这整个部分应该被锁定在文件级别(多个段不同时写入),你可能会没事。

     lock (job.FileLock)
     {
          segment.LocalStream.Seek(segment.Start + segment.BytesDownloaded, SeekOrigin.Begin);     
          await segment.LocalStream.WriteAsync(buffer, 0, read);
     }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM