A good programmer is a lazy programmer, because he writes minimum code.

Tuesday, September 29, 2009

Active Threads in a Thread Pool (How I solved a problem)

I wanted to get number of threads active in the ThreadPool. Our client wants this to be logged. I thought it is walk on the park when I found the function ThreadPool.GetAvailableThreads. However, when I read more in MSDN, I found I was wrong.

The first question that came to my mind is why Microsoft is doing a Get and Set methods, instead of using a Property. More MS style was ThreadPool.AvailableThreds. Why not that way? Why the Java style getters and setters? I found the reason soon. Even though the name contains a Get, it returns void. then how can I get the available thread count? GetAvailableThreads has two byref parameters. See the declaration.

Public Shared Sub GetAvailableThreads ( _
ByRef workerThreads As Integer, _
ByRef completionPortThreads As Integer _
So we need to declare two int variables and pass it to this function. Then how the workerThreads and completionPortThreads differ?

Before proceeding further I found that GetAvailableThreads doesn't return number of active threads, rather it gives you number of threads that you can create (or queue) more. For example, if the Thread Pool maximum size is 10 and there are 3 active threads, then GetAvailableThreads returns 7 (10 - 3). That means you can queue seven more threads.

oh! That means more work for me. I need to find out maximum threads then I can subtract available threads from it, so that I will get active threads count. Good.

So, I found a GetMaxThreads method.

Public Shared Sub GetMaxThreads ( _
ByRef workerThreads As Integer, _
ByRef completionPortThreads As Integer _

Again, the previous question. What's completionPortThreads? I found the answer here. Here is the abstract.

"The worker thread is the one we all should be immediately familiar with. You are able to run tasks on a thread pool worker thread using ThreadPool.QueueUserWorkItem. There is currently a default maximum of 500 worker threads, but this may change in the future. You can also explicitly set the maximum number of worker threads using ThreadPool.SetMaxThreads.

The completion port threads are threads that are specifically designed to be used for asynchronous I/O operations. These threads wait on a single I/O completion port (IOCP). The .NET thread pool has exactly ONE IOCP. There is currently a default maximum of 1,000 IOCP threads, but this may change in the future. You can also explicitly set the maximum number of IOCP threads using ThreadPool.SetMaxThreads. You cannot set a maximum value less than the number of CPUs in the machine."

Ok, so I don't want completion port threads. I want only workerThreads. Now I have enough information to start coding.

The first thing I need is maximum thread counts.
' get maximum worker threads
Dim maxWorkerThreads As Integer
Dim maxIOThreads As Integer
ThreadPool.GetMaxThreads(maxWorkerThreads, maxIOThreads)
So, I have maximum threads count in the variable maxWorkerThreads. Now I need to find out available threads count same way.
' get remaining worker threads
Dim availableWorkerThreads As Integer
Dim availableIOThreads As Integer
ThreadPool.GetAvailableThreads(availableWorkerThreads, availableIOThreads)
Now, I have available threads count in availableWorkerThreads variable. The rest is easy.
activeThreads = maxWorkerThreads - availableWorkerThreads

I have deployed this to the QA server and about to leave office, when the testers stopped me. They have set MaxThreadCount to 1 (Oh! I did it earlier. I allowed them to set maximum threads through a configuration file). But again, it is showing 4 threads. I reviewed the code and imagined where the code can go wrong. I found the answer easily. The ThreadPool.SetMaxCount is not working. Microsoft did some thing bad here. But I thought it again. If I go to my manager and say Microsoft did some buggy code, she is not going to believe me. Is there any other way I can go wrong? I thought before saying any one Microsoft cheated us, better to read the documentation. I did, and immediately found the answer.

"You cannot set the number of worker threads or the number of I/O completion threads to a number smaller than the number of processors in the computer."

I immediately checked how many processors are there in the server. For my relief, I it was 4. With this MSDN URL, I can convince any one that it is not my fault.

That's how I solved a problem. Just posting in hope that it would help some one else.


No comments:

Post a Comment