Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add pause/resume functionality to an application?

I'm writing an app, where most of the work is done by background threads (10 - 500 threads).

I'd like to add pause/resume functionality.

Before, you could do that with Thread.Suspend and Thread.Resume. But those functions are considered obsolete now.

Is there anything that would let me do the same with equal ease?

I'm writing the software in c#

like image 992
Arsen Zahray Avatar asked Oct 10 '11 15:10

Arsen Zahray


2 Answers

Having written a high performance crawler in C#, I can say with some authority that explicitly managing dozens or hundreds of threads is not the best way to go. It can be done (I did it), but it's painful in the extreme.

That said . . .

If your application is written the way I think, then each thread does something like this:

while (!Shutdown)
{
    // get next url to crawl from somewhere
    // download the data from that url
    // do something with the data
}

Pausing the threads between downloads is pretty easy. I would suggest making two ManualResetEvent instances: one for continue, and one for shutdown. These are static so that all crawler threads can access them:

static ManualResetEvent ShutdownEvent = new ManualResetEvent(false);
static ManualResetEvent ContinueEvent = new ManualResetEvent(true);

Then, each thread uses WaitAny in a loop:

WaitHandle[] handles = new WaitHandle[] { ShutdownEvent, ContinueEvent };
while (true)
{
    int handle = WaitHandle.WaitAny(handles);  // wait for one of the events
    if (handle == -1 || handle >= handles.Length)
    {
        throw new ApplicationException();
    }

    if (handles[handle] = ShutdownEvent)
       break;  // shutdown was signaled

    if (handles[handle] == ContinueEvent)
    {
        // download the next page and do something with the data
    }
}

Note that when I defined the handles array, I specified ShutdownEvent first. The reason is that if multiple items are signaled, WaitAny returns the lowest index that corresponds to a signaled object. If the array were populated in the other order, then you wouldn't be able to shut down without pausing first.

Now, if you want the threads to shut down, call ShutdownEvent.Set. And if you want the threads to pause, call ContinueEvent.Reset When you want the threads to resume, call ContinueEvent.Set.

Pausing in the middle of a download is a bit more difficult. It's possible to do, but the problem is that if you pause for too long the server might timeout. And then you'll have to restart the download from the beginning or, if the server and your code support it, restart the download from the point at which you left off. Either option is rather painful, so I wouldn't suggest trying to pause in the middle of a download.

like image 160
Jim Mischel Avatar answered Oct 12 '22 22:10

Jim Mischel


What does your app do?

500 threads is far too many - that's 1/2 GB of committed memory just for the stacks. And then you have all the context switching.

Good that you want to get rid of the Suspend and Resume calls, but I suggest you have a look at your architecture first - can you move to APM methods ( BeginXXX / EndXXX )?

like image 31
Nick Butler Avatar answered Oct 13 '22 00:10

Nick Butler