Question

I stay away from Application.DoEvents, since there is the issue of re-entrancy and there is always another way to avoid holding up the UI. I've long prefered to do background work in the Application.Idle event as a simple alternative to multi-threading. But, for long-running tasks, is it acceptable to run operations in Application.Idle with a DoEvents loop?

class LongRunningTask : IDisposable {

    public LongRunningTask(IEnumerable<Tidbit> listOfDataToBeProcessed) {
       Application.Idle += OnIdle;

        foreach(Tidbit t in listofDataToBeProcessed) {
            tidbits.Enqueue(t);
        }
    }

    // Small pieces of data to process
    Queue<Tidbit> tidbits = new Queue<Tidbit>();

    void OnIdle(object sender, EventArgs e) {
        while(tidbits.Count > 0) {
            var tidbit = tasks.Dequeue();
            tidbit.Process();
            // Process any messages that have queued up
            // while the data was being processed
            Application.DoEvents();
        }
    }

    public void Dispose() {
        Application.Idle -= OnIdle;
    }
}

The logic here is that in the Application.Idle event, where we call DoEvents, there are no messages queued, so we should not be able to re-enter code. Each tidbit would be processed quickly enough that it should not hold up the message queue (or UI) significantly.

So, is there any harm or drawback to this approach? Namely, is it safe to call DoEvents in the Idle event? I do know that C# 5 will have a feature to address this sort of situation, but for those of us who aren't using C# 5 (which is most of us at the moment), and out of general curiosity, is this a good plan? Or is there a simpler alternative to process messages during a long-running operation without resorting to multi-threading?

Please don't think that I imagine this to be a magic bullet. I know that it comes with the same pitfalls as any asynchronous approach. I am aware that one must still be able to keep his application in a consistent state. And I am aware that there are multithreaded solutions. I am avoiding those. Why? Because multi-threading is more complicated. I don't think that that's impractical.

Was it helpful?

Solution

What you're doing here looks a lot like Cooperative multitasking. It's an interesting idea but I would say that you should really use multi threading for something like this. .NET has a lot of helper systems like Task.Factory.StartNew() and the TPL libraries that really make it easy.

I would advise against it.

To be clear though: I do not have a clear reason against it. As with a lot of areas concerning programming: if it works, it works. However, you are mixing things together that should not be mixed together, specifically background tasks and UI tasks. I believe that when you separate the background tasks and start go get your hands dirty with multi threading, thread pools, background tasks and TPL, you'll quickly see that it does work and makes life easier in the long run.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top