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#
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.
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 )?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With