0

I have a C++ program that spawns processes. The user tells me how many cores we have to work with, and how many tasks they would like to run.

Say the user tells me they have 8 cores to work with, and they need to run 20 of our tasks. Then I spawn 8 tasks initially, and as each one of them finishes, I spawn a new task until we finish the 20 tasks.

My program works on Windows (MSVC 11) and Linux (GCC 4.8), so the implementations differ for those platforms, but in general, I'm using semaphores to keep track of the spawned processes.

My question is: what's a reasonable way to limit the number of cores the user can use? I would like to error out at the beginning of the program if the user tells us some number of cores that's not really feasible to work with. But I'm not really sure how to get a concrete number since it depends on the user's machine and the platform.

For example, I know that for Windows, I use WaitForMultipleObjects() and so I'm limited to MAXIMUM_WAIT_OBJECTS = 64 processes I can wait on (see here). But is there anything like this for Linux? Or even other "gotchas" like this in Windows?

I guess I'm looking for some standard good practices for setting such a limit.

Thanks.

Community
  • 1
  • 1
tomocafe
  • 1,425
  • 4
  • 20
  • 35
  • 1
    [This](http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine) may be useful. – lcs Feb 10 '15 at 18:42
  • @cocarin: thanks, that does look very useful for calculating the number of cores available. However, I am not sure I can just take the number of cores as the limit... for instance, if the user has 128 cores available on their Windows machine, they still won't be able to use them all due to the limit of 64 processes we can wait for. – tomocafe Feb 10 '15 at 18:45

1 Answers1

0

WaitForMultipleObjects is nice, but it's not the only way to do things. There are other ways of waiting for multiple threads or processes. For example, you could wrap the task in a thread that executes the task and then puts the result (or just a notification) on a queue and trips a common manual reset event. The spawning process waits on that manual reset event and when it trips, empties the queue. That way you're never waiting on more than one event and you can have an unlimited number of concurrent tasks (consistent with hardware limitations, of course).

This assumes that you have a thread-safe queue or a list that you can use as a queue.

Depending on what exactly your application does, you could also restructure it so that you create N threads (N being the number of cores to use), and each thread removes tasks one at a time from a common queue. It would be something like:

QueueOfTasks  // at global scope

// each thread proc
while (Queue of tasks is not empty)
{
    Dequeue task
    Execute task
    Do whatever post-task processing is necessary
}

There, you don't need any wait handles. You have N persistent threads that are reading from the common queue. No orchestration is required.

I particularly like this last solution because it involves much less platform-specific code.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351