Reputation: 2183
I have the following construct: A base-class which does some loading tasks asynchronously and a inherited class which only converts the result of the base-class into a special data-type (it's just a generic version with some extensions, but those are not of importance).
I initially call the inherited class' Process-method:
public TOut Process(object parameters)
{
return (TOut) StartProcessor(parameters).Result;
}
This method calls the following method of the base:
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;
}
Now, of course, the inherited class' Process-method deadlocks because of the Result-property. But how the heck can I avoid this? I saw a lot of articles which were great for void-methods. But I got something I have to return to the calling class. Must I return a Task in the Process-method? What can I do so that this runs asynchronously whilst it still returns the object at the end?
I really don't understand that... With void-methods it's simple, but as I need to get the Result of this task, it deadlocks. I don't get how this should ever work :-/
EDIT: Here it happens obviously...
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;
});
}
Thanks
Upvotes: 1
Views: 857
Reputation: 457302
Must I return a Task in the Process-method?
That's the best solution, yes:
public Task<TOut> ProcessAsync(object parameters)
{
return StartProcessorAsync(parameters);
}
What can I do so that this runs asynchronously whilst it still returns the object at the end?
Those two statements don't make sense together. Think about it. You want it to run asynchronously and yet synchronously return the result.
The best solution is to allow the code to be asynchronous. If StartProcessorAsync
is asynchronous, then everything that calls it should be asynchronous, too. This is the natural way to write asynchronous code.
There are various hacks to try to get synchronous over asynchronous working, but none of them work in all scenarios - because, in some way, every one of those hacks must try to force the asynchronous work to complete synchronously. That just doesn't work cleanly; the best solution is to allow asynchronous work to be asynchronous.
Upvotes: 4