Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET: Mechanism for sync-ing long-running tasks

Problem description: you write a library which contains some algorithms/tasks which can take a long time to finish, for various reasons: computational, file system, network communication etc. You want to be able to:

  1. Send some progress information about the task (progress, activity logging etc.)
  2. Have a way to abort the task before completion if some external signal or property has been set.

I've implemented a framework for this, but this requires that all such tasks have to reference an assembly which contains this framework.

My question: is there an already built-in mechanism in .NET framework (3.5 or below) for the problem described above?

I know I could use events, but this would mean long running tasks would have to expose such events, which I think is an overhead. Ideally I want to have a framework which hides away multithreading issues and is dependency-injection friendly, but would not depend on an additional custom assembly and would not pollute the original interface.

I hope I described the problem well enough. If not, I can post some samples of the interfaces from my own framework.

UPDATE: OK, I think my problem description needs a bit of clarification :). When I say "long-running", I don't mean "long" in the workflow-sense. I'm working on a WinForms mapping app which does all sorts of stuff, like generating relief contours. To do this, it first has to download the elevation data files from a FTP server, unzip them and then perform some calculations. I wrote the code for this a long time ago, but in order to make it more GUI-friendly, I have to retro-fit various checks - for example, detecting that the user has clicked on the Abort button and stop the process.

So basically my concern is: how to write a code that can later (if ever) be used in a GUI environment, where you cannot simply run everything in the main GUI thread and freeze the whole application. The challenge is to find a way to make your code suitable for GUI purposes without tying it to a particular GUI platform.

like image 589
Igor Brejc Avatar asked Feb 20 '10 10:02

Igor Brejc


3 Answers

That sounds a lot like Windows Workflow Foundation.

like image 152
Mark Seemann Avatar answered Nov 03 '22 01:11

Mark Seemann


Take a look at the saga pattern. It's not built into the framework but can be implemented. Alternatively both NServiceBus and MassTransit have implementations of this. Arnon RGO has a draft from his book (will it ever be finished) describing it here.

In my experience getting going with NServiceBus is much simpler than WF, and is also more powerful (though I haven't looked at WF 4, which by all descriptions is a near complete rework of WF as Microsoft have recognised the failings of this).

Even if you don't want a framework like NServiceBus or MassTransit, the pattern itself, is well worth looking at as it fits your problem space very closelyfrom what you have described.

like image 32
Neil Avatar answered Nov 03 '22 02:11

Neil


It depends on how complicated your system is. For relatively simple problems, you could probably nicely use the BackgroundWorker class from .NET 2.0. It supports reporting the progress of the operation using OnProgressChanged event and it also supports cancelation of the background task using CancelAsync method.

The class is controlled by events, but since that's already a part of the class, I don't think it is any overhead for you:

var bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(RunWorkerCompleted);
bw.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
  • The DoWork method is executed to run the background task (it can report progress by calling bw.ReportProgress and check for pending cancellation using bw.CancellationPending).

  • The RunWorkerCompleted method is executed on the GUI thread when the operation completes (which gives you a nice way to synchronize without worrying about concurrency)

  • The ProgressChanged event is triggered whenever your DoWork method reports some progress change.

For simpler problems, I believe you could represent your tasks as background workers.

like image 40
Tomas Petricek Avatar answered Nov 03 '22 02:11

Tomas Petricek