Can't catch Control-C  
Author Message
SheepNine





PostPosted: Visual C# General, Can't catch Control-C Top

Hey,

I'm writing an application which relies heavily on the thread pool (on the order of more than a quarter million queued user work items). I'm also trying to program graceful program termination when control-C is pressed. I've got a Console.CancelKeyPress event set up and Console.TreatControlCAsInput is false, and before my user work items are queued, everything works fine and the handler gets called. However, once I start my massive parallel processing, the handler no longer gets called - pressing control-C does nothing for about thirty seconds, then the program is abruptly terminated without running the handler. I read in the documentation that CancelKeyPress events are run on thread pool threads, and I think it has to do with there not being any available.

Is there a solution to this, or will I have to rework my jobs to not use the thread pool so there is a thread available to the event handler



Visual C#19  
 
 
Peter Ritchie





PostPosted: Visual C# General, Can't catch Control-C Top

Have you expanded the thread pool from the default # of threads Have you tried doing the same with not so may queued work items

 
 
SheepNine





PostPosted: Visual C# General, Can't catch Control-C Top

Min and max threads are both at 100 worker, 1000 I/O.

I can't get around the number of queued work items.

My supervisor has said that the control-c issue isn't very important and to move on to other things, so I'm going to leave the issue unresolved. But I recommend that someone at MS looks into this.


 
 
Peter Ritchie





PostPosted: Visual C# General, Can't catch Control-C Top

 

Min and max threads are both at 100 worker, 1000 I/O.

I can't get around the number of queued work items.

My supervisor has said that the control-c issue isn't very important and to move on to other things, so I'm going to leave the issue unresolved.  But I recommend that someone at MS looks into this.

Best case, assuming each worker thread is CPU bound--meaning it is not in a wait state and is running code--and all asynchronous IO threads are in a wait state: you've got 100 active threads context switching between one another vying for CPU time (potentially 100 active context switches at given point in time).  Each context switch is extremely expensive (one MSFT employee estimates it at 2000-8000 cycles).  All that context switching is taking time away from all other threads, including the thread that is accepting and processing the Ctrl+C keystroke.  You're not getting the event instantaneously because your design is over-taxing the CPU.  Worst case, at the time of the Ctrl+C press you've got 1100 CPU bound threads with 1100 potentially simultaneous context switches.  Add into the mix that each thread will reserve 1MB of memory for its stack (default for any .NET application)--with a worst case of slightly more than 1Gb reserved memory just for the stacks (I'd have to check, but this may actually occur on the call to ThreadPool.SetMaxThreads, so this may also be the best case).  Depending on your configuration that probably means you've got MANY page faults and lots of disk thrashing (if your page file is 2Gb in size you've just reserved half of it for your thread stacks).  To that effect the documentation for ThreadPool.SetMaxThreads states "Setting the thread pool size too large can cause performance problems. If too many threads are executing at the same time, the task switching overhead becomes a significant factor."

In reality there's only 2 classes of multithreading scenarios: one CPU-bound thread and one thread mostly in a wait state (often used to maintain a responsive GUI or perform asynchronous IO) or one CPU-bound thread per processor/core (or parallel processing).  Your mention of "massive parallel processing" is only true if you have one thread per CPU/core, otherwise they're time-sliced and not in parallel--only virtually parallel.  If you design an application that doesn't follow one or both of these two scenarios you are going to notice the performance problems mentioned in the ThreadPool.SetMaxThreads documentation.

I suggest reading the above link (MSDN Magazine Sept 2005: CLR Inside Out) as it describes in much more detail why what you're doing is doomed to failure.

Jeffery Richter recently wrote an article (The ReaderWriterGate Lock) that alludes to some of these issues, presenting a class that could be used for a more effective worker queue.

...long story short, no one from MS will look into this because there's nothing they can do...