由于Result导致任务死锁

时间:2014-04-29 17:34:10

标签: c# multithreading task-parallel-library deadlock multitasking

我有以下构造:一个基类,它以异步方式执行一些加载任务,一个继承类,只将基类的结果转换为特殊的数据类型(它只是一个具有一些扩展的通用版本,但是那些并不重要。)

我最初调用继承的类'Process-method:

    public TOut Process(object parameters)
    {
        return (TOut) StartProcessor(parameters).Result;
    }

此方法调用基数的以下方法:

    protected async Task<object> StartProcessor(object parameters)
    {
        if (State == PipelineState.Running) return null;
        if (!ValidatePipeline())
        {
            Logging.Error(
                "Pipeline can't start processor: There are some broken segment chain-links. Check your segment settings.");
            return null;
        }

        State = PipelineState.Running;
        _stopwatch.Start();

        object result = await Task.Run(() => RunPipeline(parameters));

        _stopwatch.Stop();

        if (result is PipelineState)
            State = (PipelineState) result;
        State = result != null ? PipelineState.Finished : PipelineState.Failed;

        RecentProcessTime = _stopwatch.Elapsed;
        _stopwatch.Reset();
        Logging.Debug("Finished process for pipeline {0} in: {1} ms.", Identifier,
            RecentProcessTime.TotalMilliseconds);

        return result;
    }

    private object RunPipeline(object parameter)
    {
        object recentResult = null;
        for (int i = 0; i < SegmentCount; i++)
        {
            if (_cancelProcess) // Cancel process
                return PipelineState.Cancelled;

            PipelineSegmentBase seg = Segments[i];
            if (i == 0) // If first, do initial process
            {
                recentResult = seg.Process(parameter, ProcessingDirection);
                continue;
            }
            if (i > 0 && recentResult == null) // If not first and recent result was null, process failed
                return PipelineState.Failed;

            seg.Process(recentResult, ProcessingDirection); // Process
        }

        return recentResult ?? PipelineState.Failed;
    }

现在,当然,由于Result属性,继承的类'Process-method死锁。但是我怎么能避免这种情况呢?我看到很多文章都非常适合虚空方法。但是我得到了一些我必须回到调用类的东西。我必须在Process-method中返回一个Task吗?我能做什么才能让它在异步时运行,同时它仍然在最后返回对象?

我真的不明白......使用void-methods它很简单,但是当我需要获得此任务的结果时,它会死锁。我不知道这应该如何工作: - /

编辑:这显然发生在......

    public override object Process(object input, PipelineDirection direction)
    {
        if (!IsValidInput(input)) return null;
        Stream str = (Stream) input;
        // DEADLOCK
        return Core.IDE.GetGUICore().GetUIDispatcher().Invoke(() =>
        {
            Image i = new Image();
            i.BeginInit();
            i.Source = BitmapFrame.Create(str);
            i.EndInit();
            return i;
        });
    }

由于

1 个答案:

答案 0 :(得分:3)

  

我必须在Process-method中返回一个Task吗?

这是最好的解决方案,是的:

public Task<TOut> ProcessAsync(object parameters)
{
    return StartProcessorAsync(parameters);
}
  

我可以做什么,以便在最后仍然返回对象的同时异步运行?

这两个陈述并不合理。想一想。您希望它以异步方式运行 ,然后同步返回结果。

最好的解决方案是允许代码异步。如果StartProcessorAsync是异步的,那么调用它的所有东西也应该是异步的。这是编写异步代码的自然方式。

有许多hacks试图让synchronous over asynchronous正常工作,但它们都不能在所有情况下工作 - 因为,在某些方面,每个黑客都必须尝试强制异步工作同步完成。这根本不干净;最好的解决方案是允许异步工作异步。