Thread with the lowest priority is called more times
The following code has 5 threads with different priorities competing for access to a processor with 8 cores (Mac OS X 10.8.5, Mono). Each thread increments the counter.
using System;
using System.Threading;
class PriorityTesting
{
static long[] counts;
static bool finish;
static void ThreadFunc(object iThread)
{
while(true)
{
if(finish)
break;
counts[(int)iThread]++;
}
}
static void Main()
{
counts = new long[5];
Thread[] t = new Thread[5];
for(int i=0; i<t.Length; i++)
{
t[i] = new Thread(ThreadFunc);
t[i].Priority = (ThreadPriority)i;
}
//
for(int i=0; i<t.Length; i++)
t[i].Start(i);
// 10 c
Thread.Sleep(10000);
//
finish = true;
//
for(int i=0; i<t.Length; i++)
t[i].Join();
//
for(int i=0; i<t.Length; i++)
Console.WriteLine("Thread with priority {0, 15}, Counts: {1}", (ThreadPriority)i, counts[i]);
}
}
Compilation:
$ mcs PriorityTesting.cs $ mono PriorityTesting.exe
Output:
Thread with priority Lowest, Counts: 178544880
Thread with priority BelowNormal, Counts: 167783608
Thread with priority Normal, Counts: 160593225
Thread with priority AboveNormal, Counts: 79123315
Thread with priority Highest, Counts: 81623159
How is it that the lowest priority thread gets called longer than the highest priority threads?
UPD:
The same code on a CPU with 2 cores gives (Windows, .NET):
Thread with priority Lowest, Counts: 7608195
Thread with priority BelowNormal, Counts: 10457706
Thread with priority Normal, Counts: 17852629
Thread with priority AboveNormal, Counts: 297729812
Thread with priority Highest, Counts: 302506232
Why the difference?
source to share
There is no support Priority
in Mono, so the behavior you see for the youngest being called more times might just be luck.
Here's a pull request from a contributor implementing this property on github, so you can join by asking to view it.
UPDATE . This answer may be out of date. Since Mono is moving forward quickly, it's best to double-check your program, perhaps priority is working these days.
source to share
This can happen for many reasons.
There is something called "Priority promotion" and which is one of them, the operating system will raise the priority (increase the priority of threads temporarily) for various reasons. Example: a thread has just received an event signal. This is the user interface. thread that is pumping messages and there is a new message received in the queue, another reason might be hungry.
There may be hunger here. Your low priority threads will not be able to execute if there is a higher priority thread that is either ready or currently running. If a thread is starving for a long time, the operating system will raise the priority for the thread that is starving so that it immediately preempts the current threads and gets an opportunity to execute, which cancels the fast time.
I tested on windows, the results are very similar and here's an explanation. The operating system makes it possible to starve from hunger. I think something similar exists on other operating systems as well.
Windows has a service called balance set manager. It runs asynchronously on a system thread looking for hungry threads; these are threads that have been waiting for 4 seconds or longer to start in a ready state. If it finds one, it will give the thread temporary priority. It always raises the priority of a hungry thread to level 1 5, regardless of its current value. This is done to combat hunger, for example when many higher priority threads are constantly running so that lower priority threads never get a chance to execute.
Quote from the book Parallel Programming on Windows-Joe Duffy
Update:
Regarding your updated results on Windows with 2 cores, yes, the results are not surprising, there is not enough CPU to start threads that are in ready state, so the operating system has to wait until other threads finish their Thread Quantum. There are higher priority threads than lower ones, so obviously the operating system prioritizes higher priority threads.
For results with 8 cores: as stated, mono does not support priority, you started a lower priority thread first and you have enough CPUs to run the running threads. Thus, there is no need to supplant lower priority topics here. Thus, the operating system allows threads to run without disruption (preemption). Try testing with more threads than the processor. This is where priority really comes into picture.
source to share
The downstream with the lowest priority starts first. This gives a lower priority time to start, while higher priority threads are started (starting a thread is not a trivial operation).
Create another boolean flag to adjust the counting in the thread function so that all threads are started before any of them starts counting:
static long[] counts;
static bool finish;
static bool count; // add this
static void ThreadFunc(object iThread)
{
while(true)
{
if(finish)
break;
if( count ) // only count when ready
counts[(int)iThread]++;
}
}
In Main
:
// After your loop to start the threads
// set the count flag to start counting
count = true;
// 10 c
Thread.Sleep(10000);
source to share
First of all, do not confuse it with thread priority. Or the priority of the process. You won't be of any help and you will probably run into a lot of deadlocks and other synchronization issues that come in handy, which will be very fun to debug. Trust the OS thread scheduler to get the job done - it's actually pretty good!
Second, Mono does not support priorities.
Third, you might want to give threads enough work to actually give them a reason to switch. The five threads on an eight core processor aren't going to cause enough conflicts to warrant any thread switches at all, and they can just run at the same pace. To experiment with thread priorities, you need more threads than CPU cores. And yes, Hyper-Threaded kernels are also counted.
Don't just make a "stupid" counter - add stupid work for the processor at every step of the counter, for example Thread.SpinWait(100000)
. This will incur a stupid blow to the processor, making your score more interesting and comparable.
I've never seen a good case for changing thread priorities. Always the best solution and you are most likely trying to solve a problem that either doesn't exist or can be solved much better. A good starting link for priority issues is disabled. Jeff Atwood http://blog.codinghorror.com/thread-priorities-are-evil/ .
Note that constructs with a higher level of multithreading / parallelism such as Task
have no way to suggest precedence or anything like that - there is a good reason for that.
Take care :)
source to share