【问题标题】:Deadlocks in async method using TaskCompletionSource使用 TaskCompletionSource 的异步方法中的死锁
【发布时间】:2018-09-12 08:02:05
【问题描述】:

我正在尝试公开一个 ASP.NET Web API,它必须捕获照片并将其作为附件返回。 我正在使用CameraControl.Devices 2.1.0-beta 来控制我的尼康数码单反相机和.NET 4.6。

但我的行为非常不一致。有时第一个 HTTP 请求会设法返回一张照片,但从那里开始它会在组成最终的 HttpResponseMessage 之前停止,然后 HTTP 请求就会挂起并超时。我相信这是由异步操作引起的死锁。它始终执行 DeviceManager_PhotoCaptured 中的逻辑,将照片从 DSLR 传输到文件夹。有时它甚至会从一个请求中获取两张照片。

我做错了什么?你知道更好的方法吗?

using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using CameraControl.Devices;
using CameraControl.Devices.Classes;

public class PhotosController : ApiController
{
    public string FolderForPhotos = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Test");

    private TaskCompletionSource<string> TaskCompletionSource = null;
    private CameraDeviceManager DeviceManager = null;

    // GET api/photos
    public async Task<HttpResponseMessage> Get()
    {
        TaskCompletionSource = new TaskCompletionSource<string>();

        DeviceManager = new CameraDeviceManager();
        DeviceManager.StartInNewThread = false;
        DeviceManager.PhotoCaptured += DeviceManager_PhotoCaptured;

        DeviceManager.ConnectToCamera();
        DeviceManager.SelectedCameraDevice.CapturePhoto();

        var fileName = await TaskCompletionSource.Task.ConfigureAwait(continueOnCapturedContext: false);

        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        var stream = new FileStream(fileName, FileMode.Open);
        result.Content = new StreamContent(stream);
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(fileName);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
        result.Content.Headers.ContentLength = stream.Length;
        return result;
    }

    private void DeviceManager_PhotoCaptured(object sender, PhotoCapturedEventArgs eventArgs)
    {
        if (eventArgs == null)
        {
            TaskCompletionSource.TrySetException(new Exception("eventArgs is empty"));
            return;
        }
        try
        {
            string fileName = Path.Combine(FolderForPhotos, Path.GetFileName(eventArgs.FileName));
            // if file exist try to generate a new filename to prevent file lost. 
            // This useful when camera is set to record in ram the the all file names are same.
            if (File.Exists(fileName))
                fileName =
                    StaticHelper.GetUniqueFilename(
                    Path.GetDirectoryName(fileName) + "\\" + Path.GetFileNameWithoutExtension(fileName) + "_", 0,
                    Path.GetExtension(fileName));

            // check the folder of filename, if not found create it
            if (!Directory.Exists(Path.GetDirectoryName(fileName)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(fileName));
            }
            eventArgs.CameraDevice.TransferFile(eventArgs.Handle, fileName);
            // the IsBusy may used internally, if file transfer is done should set to false  
            eventArgs.CameraDevice.IsBusy = false;

            TaskCompletionSource.TrySetResult(fileName);
        }
        catch (Exception exception)
        {
            TaskCompletionSource.TrySetException(exception);
            eventArgs.CameraDevice.IsBusy = false;
        }
        finally
        {
            DeviceManager.CloseAll();
        }
    }
}

【问题讨论】:

    标签: c# asp.net .net asp.net-web-api taskcompletionsource


    【解决方案1】:

    我想通了:

    我必须将TaskCompletionSource 设为静态字段。我想,出于某种原因,当它是一个实例字段时,它最终会被释放或分离。 private static TaskCompletionSource<string> TaskCompletionSource = null;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-18
      • 1970-01-01
      • 2014-09-12
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多