Why *not* change the priority of a ThreadPool (or Task) thread?

13,260

Solution 1

The thread pool, especially the .NET 4.0 thread pool, has many tricks up its sleeve and is a rather complicated system. Add in tasks and task schedulers and work stealing and all sorts of other things and the reality is you don't know what is going on. The thread pool may notice that your task is waiting on I/O and decide to schedule something quick on your task or suspend your thread to run something of higher priority. Your thread may somehow be a dependency for a higher-priority thread (that you may or may not be aware of) and end up causing a deadlock. Your thread may die in some abnormal way and be unable to restore priority.

If you have a long-running task such that you think it would be best that your thread have a lower priority then the thread pool probably isn't for you. While the algorithms have been improved in .NET 4.0, it is still best used for short-lived tasks where the cost of creating a new thread is disproportional to the length of the task. If your task runs for more than a second or two the cost of creating a new thread is insignificant (although management might be annoying).

Solution 2

I've done some experimentation with a reduced-size thread pool which seems to indicate that the thread's priority is reset back to normal once returned to the pool. This resource on threading seems to confirm it. So the effect seems to be very limited even if you do.

Solution 3

Lowering the priority could also lead to unexpected consequences.

Imagine you schedule a task in an application, but also call into a library that schedules several other tasks. Say you lower the thread priority while the app task runs. You could then end up with the normal priority tasks in the lib waiting for that low priority task to finish, if the pool doesn't spawn many threads, but the low priority thread it may not be given much CPU time if the rest of the system has many normal priority threads that want to run.

Increasing the number of pool threads would alleviate this, at the cost of wasting more memory on stacks and spending more CPU time on context switches.

Share:
13,260

Related videos on Youtube

Glenn Slayden
Author by

Glenn Slayden

I am the author of agree, a parser and tactical realization (generation) system which supports natural language grammars within the framework of the DELPH-IN joint reference formalism. A long-term aim is to deploy bidirectional Thai-English analytical machine translation at my website, http://www.thai-language.com.

Updated on April 27, 2020

Comments

  • Glenn Slayden
    Glenn Slayden almost 4 years

    There are many places across the web and Stack Overflow where one is discouraged from changing the priority of a ThreadPool thread or TPL Task. In particular:

    "You have no control over the state and priority of a thread pool thread."
    "The runtime manages the thread pool. You have no control over the scheduling of the thread, nor can you change the thread's priority."

    "You should not change the Culture or Priority or... of a PoolThread. Just like you don't paint or re-decorate a rental car."

    "There are several scenarios in which it is appropriate to create and manage your own threads instead of using thread pool threads: (such as...) You require a thread to have a particular priority."

    "Each thread in ThreadPool runs at the default priority and the code to change the ThreadPriority has no effect."

    However, it is a simple matter to do so, and the debugger shows that the change does seem to stick (insofar as the value can be read back).

    Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
    

    So the question is, what is the specific reason for this particular taboo?

    My suspicion: doing so disturbs the delicate load balancing-assumptions of the pool. But this doesn't explain why some sources say that you can't change it.

  • Glenn Slayden
    Glenn Slayden about 13 years
    I should have mentioned that you could restore the original priority when you're done with the thread or task...
  • user541686
    user541686 about 13 years
    @Glenn: It's simply not meant to be changed. There's no CLR police to handcuff you if you do, but it's considered bad practice because thread pools are not meant to have an identity.
  • Adam Spicer
    Adam Spicer almost 13 years
    Not helpful. Question is about WHY or WHY NOT.
  • Joe
    Joe almost 13 years
    @Adam - I disagree that this is unhelpful. The reasons are covered in other answers, but if after considering the trade-offs someone decides to go ahead and to it, then reverting to the original state in a finally block so that it happens even in the event of an exception is good practice, and may easily be forgotten.
  • Adam Spicer
    Adam Spicer almost 13 years
    Check out Michael's answer. It points out a great thread pool resource that states "You are free to change the priority of a pooled thread — it will be restored to normal when released back to the pool."
  • Joe
    Joe almost 13 years
    @Adam - interesting, but it would be nice to see official documentaiton confirming it before relying on it. Otherwise you'd have to consider it as an implementation detail that can't be relied upon. And what about other attributes of the thread such as culture? I still maintain that restoring state in a finally block is good practice in the absence of official documentation saying it's unnecessary.
  • Chris Moschini
    Chris Moschini over 12 years
    I agree this is unhelplful because of the below answer - that is, even if you do modify it, it doesn't stick. As soon as it goes back to the thread pool it's reset. It appears the ThreadPool protects itself from this type of meddling, so try/finally is just adding a performance burden with no improved result.
  • AlwaysLearning
    AlwaysLearning about 9 years
    @Joe: try/finally is not the correct way to manage this in the context of .NET TaskFactory Tasks. (Managing your own Threads directly is another matter.) Imagine your Task calls a library function that, for whatever reason, uses a Wait() or a Sleep() somewhere... when execution returns to your Task's code it may well be a completely different Thread from the Thread Pool and your original Thread is off being used by another Task. For example, [stackoverflow.com/a/12246045/390122]

Related