views:

27

answers:

2

Now I'm in such a situation that there is a group of predefined tasks for multiple clients to do(any client can take any task). When a client connects to the server, server choose a task from the uncompleted tasks and send it to the client --- job on the server side is quite easy. It takes a while for the client to finish the task and send the result back to the server.

Since a task should be sent to only one client, server should process requests in a serialized way. Now I have two plans to do it: create a thread for each client connection and all the threads take turns accessing the task pool, or use epoll listening on all the connection and process for each event of clients.

Which one is better for the job? Or is there any other ideas? The server will be run on a multi-core machine.

+1  A: 

The main question is whether the server has significant processing to do in order to prepare the tasks for the client. If not, there's nothing to be gained from using multiple threads -- on the contrary, the context switching will just add overhead. In this case it would be the best to use epoll (most likely via some existing library, depending on the programming language you're using).

If there is significant processing on the server side, it may offset the inefficiency of context switching, and improve performance by gaining parallelism from multiple core. The only way to know for sure what the best solution will be is to do some prototyping and profiling.

Are the clients running on the same machine as the server is? If they are, you'll be able to utilize the multiple cores easily.

gavrie
@gavrie: Preparing the task is small job. Thanks for that. I'll put that into my question. And clients run on different machines.
hpsMouse
A: 

You can do both. You can have multiple threads running epoll() on the same fd-set, and the operating system will wake up threads as needed. It's also really easy to do this- especially if you don't need any sharing: Simply fork() fifty times or so and Linux will context switch if needed, and epoll when not. When I do this, I simply do something like this:

{char*s=getenv("THREADS");int n=atoi(s?s:"0"),i;
 for(i=0;i<n;i++)if(fork()==0)break;}

If you do need sharing, then you're going to need locking. This can complicate things here, and these kinds of programming problems are difficult to solve in a general sense. It is my experience that except in the case of some very simple databases, it is usually simpler to either forgo threads, or re-engineer the program to not require locking on the shared structures.

geocar
@geocar: Thanks for the advice. But I don't want the program to be so complicated. I would rather write it in a simpler way.
hpsMouse