views:

117

answers:

3

I'm trying to gain a better understanding of how multi-core processors work and how as a programmer I can take advantage of them.

Let's say I have a standard .net console app. It doesn't do any multithreading. Does it only run on 1 of the cores? If so which core does it run on and is it the same one everytime?

Now let's say I have another console app that spins up a bunch of threads internally. Do the threads get divided up amongst the available cores or all they all run on the same core the the initial thread is on and I have to do something special to use the other available ones?

A: 

a standard .net console app. It doesn't do any multithreading. Does it only run on 1 of the cores?

Yes

console app that spins up a bunch of threads internally. Do the threads get divided up amongst the available cores

Yes

or [are] they all run on the same core the the initial thread is on and I have to do something special to use the other available ones?

No

But you have yet to face the main problem: When those threads want to share data.

And "spinning up a bunch of threads" only improves performance up to the number of cores. Running too many threads will slow you down.

Henk Holterman
@Henk: The app may jump cores if the OS decides it wants to move it...
Reed Copsey
@Reed, correct but it will only run at 1 core at a time. A jump will be really transparent to the code.
Henk Holterman
+5  A: 

Most operating systems use preemptive multitasking to schedule applications as they run.

Does it only run on 1 of the cores? If so which core does it run on and is it the same one everytime?

No, and no. The OS is free to stop the process mid-run, and move it to a different core. This happens regularly. If it's single threaded, however, your application code will only run on one core at a time. (In .NET, the process always uses extra threads for things such as garbage collection, and the BCL will often use threading internally.)

Now let's say I have another console app that spins up a bunch of threads internally. Do the threads get divided up amongst the available cores

Ideally, yes. In practice, the OS will often use some of the resources, and the threads may get moved around between cores, etc.

or all they all run on the same core the the initial thread is on and I have to do something special to use the other available ones?

No. Most of the time, the threads are pushed onto other cores, especially if they are idle. This is up to the operating system, however.

That being said, some operating systems allow you to specify processor affinity for a specific thread, which allows you to place a thread onto a specific processor and leave it there. Most operating systems only treat this as a suggestion (and will still move them), but many embedded systems will honor the requests fully.

Reed Copsey
+1. Additionally, depending on the version of the .NET framework, garbage collection may occur on a separate thread. Also, there exist methods in the .NET BCL which may internally use multiple threads to execute if necessary. Specifically, the WCF and WF frameworks come to mind. If these APIs are consumed you may end up using more than just a single thread as well.
LBushkin
@LBushkin: Very true. I added that into my answer.
Reed Copsey
+8  A: 

The relationship between cores, threads, processes, and classes can be a complicated one. More so when you start considering how code you may not have written (e.g. the .NET framework itself) is scheduled to run.

The simplistic answer is that unless you specifically write your console application to use multiple threads, it will run on a single core.

Now, there are some .NET framework classes that behind the scenes may use multiple threads, in which case your process may utilize more than one core even then. Much of the BCL doesn't use threads, but frameworks like WCF and WF may internally use threading.

Furthermore, the runtime environment may uses multiple threads (in some instances) for things like garbage collection. Beyond even that, the runtime environment may move your code from core to core. This occurs because the OS itself uses pre-emptive multitasking to schedule threads - and so a single thread isn't guaranteed to have affinity to a particular core.

For the second part of your question, if a process spawn threads explicitly, they will usually (but not always), end up on separate cores. Most of the time, these threads will be scheduled to run on whichever core has capacity - and threads (as I mentioned earlier) may move from core to core. You should not have to do anything special (usually) to get multiple cores to run your code.

It's actually the inverse that is sometimes harder to achieve: ensuring that a particular thread only runs on a single core. This is referred to as affinity. In certain cases it is desirable to affinitize a thread to a particular core to improve locality of reference and minimize potential for cache misses. Most of the time, however, you don't need to worry about this.

If you're interested in learning more about concurrent programming on Windows (and in .NET) I would suggest you pick up a copy of Joe Duffy's Concurrent Programming on Windows.

LBushkin
Good point about the GC ;) .NET apps always use multiple threads because of this...
Reed Copsey
This answer applied to more than just .NET applications; other systems will show similar behavior, especially when using large frameworks or libraries.
Karmastan
Is there any way to request that a multi-thread application not use multiple cores simultaneously, so as to ensure memory consistency between threads?
supercat
@supercat: What exactly do you mean by "memory consistency"? If you have multiple threads running in a process you already have to perform some kind of concurrency control on shared memory to prevent inconsistent reads or corrupting data. Multiple cores don't really change that aspect of concurrent development. But perhaps you mean something else?
LBushkin
@LBushkin: If code is run on a single processor, I believe the processor is required to behave as if instructions are executed in order, even in the presence of context switching. If code is run on multiple cores, however, there's no such guarantee. Even on a single CPU, compilers may munge things in annoying ways, but it should be possible to control that without needing hard memory barriers on everything.
supercat
@supercat: I see what you're referring to. It is possible to affinitize all of your application's threads to a single core using [`SetProcessAffinityMask()`](http://msdn.microsoft.com/en-us/library/ms686223(v=vs.85).aspx). In managed code the equivalent is the [`Process.ProcessorAffinity`](http://msdn.microsoft.com/en-us/library/system.diagnostics.process.processoraffinity.aspx) property.
LBushkin