Thursday 3 May 2012

Have my threads and eat them.

I plan to implement this key value store as a traditional server that multiple clients connect to over TCP/IP.  I'd like be able to handle as many simultaneous connections as possible while keeping memory usage and processing to a minimum.  Creating an operating system thread for each client as they connect is the common approach to solving this problem.  Spinning up potentially thousands of these threads is a concern when considering the resources that get allocated for each one.

There's a number of arguments claiming that needing a thread for each client is a poor approach to handling a large number of concurrent client connections.  Some languages like Erlang, implement their own lightweight processes that can be used to handle individual client connections.  Which has been used as a successful approach to solve this problem.  Using asynchronous sockets also might be a better way to implement all these connections without the need of so many threads.

For me I'd like to know what the limitations are in C for the number of concurrent threads that can be started on Windows.  So I've written the simple code below to answer this question.

#include <Windows.h>
#include <stdio.h>

// Thread Procedure
DWORD WINAPI ThreadProc(__in LPVOID lpParameter)
{
    // Sleep forever

    Sleep(INFINITE);

    return(0);
}


// Main program
void main(int argc,char *argv[])
{

    int i;
    HANDLE thread = NULL;

    // Loop through creating threads
    for (i = 0; i < 1000000; i++)
    {
        DWORD id;
        HANDLE h = CreateThread(NULL, 0, ThreadProc, NULL, 0, &id);

        if (!h) break;
    }
 

    printf("Created %d threads\n", i);
    getchar();
}


Running this code tries to create 1 million threads.  In reality it only manages 2933 threads on my laptop.  That is until I modify the CreateThread call so it is like below.

CreateThread(NULL, 4096, ThreadProc, NULL, STACK_SIZE_PARAM_IS_A_RESERVATION, &id);

After making this change and reducing the allocated stack size for each thread we manage to create 12477 threads.  Which isn't too bad really considering that it's Windows 7 with only 4GB of memory on an Intel Celeron Dual-Core CPU T3100 @ 1.90GHz.

No comments: