What is the maximum number of threads you can create in a C# application? And what happens when you reach this limit? Is an exception of some kind thrown?
There is no inherent limit. The maximum number of threads is determined by the amount of physical resources available. See this article by Raymond Chen for specifics.
I would characterise the thread density of applications something like this:
- 1-2 threads: desktop application
- 10-20 threads: server application
- 100-200 threads: super busy server application (running on serious multicore hardware)
- 1000+ threads: doesn't happen
Jeff Richter in CLR via C#:
"With version 2.0 of the CLR, the maximum number of worker threads default to 25 per CPU in the machine and the maximum number of I/O threads defaults to 1000. A limit of 1000 is effectively no limit at all."
Note this is based on .NET 2.0. This may have changed in .NET 3.5.
[Edit] As @Mitch pointed out, this is specific to the CLR ThreadPool. If you're creating threads directly see the @Mitch and others comments.
I will not provide an answer (Mitch Wheat is right - the limit is determined by address space and stack size you want to allocate to each thread), but rather note that if you are asking this question because you hit the limit, or expect to hit the limit, you should change the design of the program.
Yes, you can create thousands of threads, but it is the wrong way to write application. If you create more than 100-200 threads (and even that number is too big), you should seriously consider using asynchronous programming models. With async API, you don't waste thread for IO, and since your threads are busy doing computations, not waiting for IO completion, there should be no reasons to create more threads than CPUs.
Mitch is right. It depends on resources (memory).
Although Raymond's article is dedicated to Windows threads, not to C# threads, the logic applies the same (C# threads are mapped to Windows threads).
However, as we are in C#, if we want to be completely precise, we need to distinguish between "started" and "non started" threads. Only started threads actually reserve stack space (as we could expect). Non started threads only allocate the information required by a thread object (you can use reflector if interested in the actual members).
You can actually test it for yourself, compare:
static void DummyCall()
{
Thread.Sleep(1000000000);
}
static void Main(string[] args)
{
int count = 0;
var threadList = new List<Thread>();
try
{
while (true)
{
Thread newThread = new Thread(new ThreadStart(DummyCall), 1024);
newThread.Start();
threadList.Add(newThread);
count++;
}
}
catch (Exception ex)
{
}
}
with:
static void DummyCall()
{
Thread.Sleep(1000000000);
}
static void Main(string[] args)
{
int count = 0;
var threadList = new List<Thread>();
try
{
while (true)
{
Thread newThread = new Thread(new ThreadStart(DummyCall), 1024);
threadList.Add(newThread);
count++;
}
}
catch (Exception ex)
{
}
}
Put a breakpoint in the exception (out of memory, of course) in VS to see the value of counter. There is a very significant difference, of course.
You should be using the thread pool (or async delgates, which in turn use the thread pool) so that the system can decide how many threads should run.