2

Tpl and Plinq automatically assign work to threads (at core/s... {well ,if #threads> #cores then , >1 thread will run on the same core. }).

However , Let's say I have MyMethod1(){..} and MyMethod2(){..} and I need to make sure(!) that each will run on a different core! (e.g. intensive computing)

The nearest solution I found is Plinq's .WithExecutionMode (ParallelExecutionMode.ForceParallelism)

But this is for a different situation where Plinq might think that it is better to do it sequentially rather then parallel.Also ,I dont use Plinq. I only have 2 methods which needs to run on a different core.

How can I do it ?

p.s. there was an answer here at SO which suggested to use TaskCreationOptions.LongRunning but it is only to hint to the TaskScheduler that it should more aggressively create thread pool threads. but those threads can be on the same core. and my situation required them to be at a different core.

Thank you.

Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • I don't think you can have that much control over where thread will run even in WinAPI, AFAIK the OS decides on which core the thread will run - [link to related question](http://stackoverflow.com/a/2889990/1180426) – Patryk Ćwiek Mar 30 '13 at 12:53
  • If your hardware has at least two cores and sufficient grunt that it is not overloaded with ready threads, would what you seem to need not happen anyway? – Martin James Mar 30 '13 at 14:03
  • @MartinJames I was thinking that Windows will **not** know (at the beginning) that the threads are running massive calculations - and therefore - it can schedule both threads on the same core. – Royi Namir Mar 30 '13 at 14:19
  • 1
    The OS moves threads between cores automatically though. http://stackoverflow.com/questions/1579002/net-movement-of-threads-between-cores – Matthew Watson Mar 30 '13 at 14:27
  • @RoyiNamir it cannot dispatch more than one thread on a core. If there are two free cores and two ready threads, it will dispatch one thread onto each core. – Martin James Mar 30 '13 at 17:51
  • Also, I can't see how it could not swap threads on cores. If thread A is running on core 1 and gets blocked on something, it is no longer running. If A becomes ready again while thread B is already running on core 1, but core 2 is free, it is only sane that the OS runs A on core 2. Also, if the OS finds that A and B are both running on two 'cores' that are hyperthreaded together, it may decide to move one thread to a completely independent core to improve overall performance. – Martin James Mar 30 '13 at 17:58
  • @MartinJames What makes you think that I thought it can dispatch more than one thread on a core ? every core - each time - will have its time slice on a core. but my question to Jeffery was if thread "a" and "b" was scheduled to core #0 , can windows detect that "b" is also computing intensive thread and move it to core #1 .... – Royi Namir Mar 30 '13 at 18:13
  • Don't see how it could possibly know, which is why it doesn't care. I don't understand 'thread "a" and "b" was scheduled to core #0' - if a thread becomes ready, and there is one core free, it will run it on that core if the core it previously ran on is busy running some other thread. – Martin James Mar 30 '13 at 19:23
  • @MartinJames We do agree that if there's 2 cores and many threads where 2 of them are my "intensive calculation threads" - it will take _less longer_ if each thread (my threads) will be running ( when it has its time slice) on different cores....right ? that's is my actual question.that's why TPL actually tries to do ( whenever it can) – Royi Namir Mar 30 '13 at 20:08

1 Answers1

8

To do this requires breaking down several layers of abstraction and before doing it I would recommend doing quite a bit of profiling to be certain that doing this will be better performance than letting the framework handle resource allocation. I am somewhat doubtful (though I can't say I've analyzed it).

The first thing you need to do is to make sure that your two Tasks get executed on different managed threads. Because this is trying to assert manual control over something the framework handles, to be certain that this is the case you would need to write your own TaskScheduler. However, realistically you can do this by specifying the TaskCreationOptions.LongRunning flag. On the current desktop CLR, at least, that will always create a new thread. But it's just a hint, API-wise.

The next abstraction to break is that of managed vs native threads. Each of your methods should be wrapped in a thread affinity block. The framework is allowed to switch the physical thread a managed thread is running on. Since processor affinity is a native thread operation, you have to tell the framework not to do that.

Next, you need to get the native thread that corresponds to the current managed thread. In each method, after calling BeginThreadAffinity, get the native thread by calling GetCurrentThreadId via p/invoke.

Now you can do the rest of this in either native or managed land, but I'll assume you want to do it in .NET. In that case, get the ProcessThread object which corresponds to the native thread, and you can set processor affinity or ideal processor from there:

Thread.BeginThreadAffinity();
int threadId = GetCurrentThreadId();
Process proc = Process.GetCurrentProcess();
ProcessThread procThread = proc.Threads.Cast<ProcessThread>().Single(
    pt => pt.Id == threadId
);
procThread.ProcessorAffinity = new IntPtr(0x01);
//
// work
//
procThread.ProcessorAffinity = new IntPtr(0xFFFF);
Thread.EndThreadAffinity()
Jacob
  • 1,699
  • 10
  • 11