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?

+3


source to share


4 answers


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.

+6


source


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.

+3


source


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);

      

+1


source


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 :)

+1


source







All Articles