Thread Priorities are Evil

coleman:

“If you have a while(true) loop that’s running “full tilt” you’re never giving the scheduler a chance to give time to other processes …”

Although that may be true in a cooperatively multitasking OS, it is false for a preemptively multitasking OS. In this discussion, it’s the latter we’re talking about.

“I says you need to give up a time slice so the scheduler can do it’s job.”

In a premptively multitasking OS, it is the operating system that forces running threads/processes to “give up” time to other threads/processes (that’s part of it’s job). So no, there is no need for Sleep() to give up time, unless (as has been pointed out) you are misusing priorities. If putting Sleep() inside your loop makes things better in your situation, that is a symptom of a more fundamental problem, not a real solution.

Well here are some comments from a device driver developer, who just saw a preposterous claim on his RSS feed.

Process and thread priorities are there for a reason. They have clear-cut and documented semantics. So does the scheduler. So do cars. We don’t condemn cars because some people drink and drive. We don’t condemn cars because most people have trouble controlling them at 130mps.

Why should people think that changing the priority of a CPU-hungry app to realtime and thus hogging the system is a more reasonable thing to try than jumping off a car moving at 60mps?
Both actions have well defined results, they are 2 clicks away and the “OS” definitely permits them.

Moreover, why should people think that an OS should magically protect them from anything evil that a clueless app/user/driver might do?
OK, sure, usability and robustness should always improve, but there is common sense as well.
You can blame the OS for a user misusing process priorities as much as you can blame it for allowing the user to delete all her files.

To sum up:
() Process and thread priorities are an 100% necessary feature. The design and implementation of the Windows Scheduler is quite satisfactory.
(
) Multithreaded programming is usually much tougher to get right than simple GUI programming, and involving priorities makes it a little more challenging, but nothing that a decent developer can’t digest. Decent means a bit of experience and some willingness to read the documentation, rather than mindlessly copy-paste from CodeProject some code they don’t really understand.

I would be interested in knowing what OS X and Linux are doing that somehow makes some people happier, and why Windows is not doing it. Anybody know? Obviously, there are pros and cons to every scheme, so nothing is going to be perfect.

I do wish Windows would be a bit more granular about how often it boosts the priority of low-priority starving threads. Instead of getting 20 ms every 4 seconds, I would prefer that the starving threads got 1 ms every half-second or so. Much easier to interact with the system that way. However, this does mean the system spends more time context switching and less time working, but in some cases that might be preferable.

In my experience, Windows usually does an ok job of scheduling the CPU. The biggest issues come up when one process monopolizes some other resource, such as disk IO. That is when things really start bogging down.

I was just wondering if any of you guys can answer this question:

If a process is suspended(put on wait), will its thread also be suspended

And what is an example of this

A comment on the last quote, the Joe Duffy quote.

The only reason the producer will be starved is that the consumer is using busy-wait instead of a system-supplied synchronizing object. Using that object, the thread would be “not-running”, thus not starving the producer.

Thread priorities are not evil, people writing bad code are evil, and they hog my computer.

I sometimes reduce the priorities of processes that are taking 100% CPU time, but that is is for what I do with priorities.

Your reall issue sits not with thread priorities, or even process priorities (your article mixes the two) but really with the Windows scheduler. It does not propperly pre-empt processes, it instead appears to wait for the process to yield, and just gives starts based on priority. As another user, who uses Mac OSX, mentioned, one task at 100% does not kill the machine. I use primarily Linux, and have the same observation.

I’ve been glad that thread priorities can be changed by me as an end user when an application is preventing me from working. My only other option at that point is to kill the process, which can leave things in a sorry state. An example was RSSBandit on 1500 feeds - it would hang like crazy on a single proc box when updating feeds, but if I set the thread priority to low I could let it update in the background and keep working.

That’s a great point on the real utility of dual proc boxes being insurance against un-responsive applications rather than blazing speed on normal operations (which I haven’t found to be the case). It would be nice if Windows eventually changes CD / DVD access so it only drags down a single proc, although I’m sure that would be a complex task. Anyone know if this is better in Vista?

I was a little surprised to hear that one of the new features of Windows Media Player is that it runs at a higher thread priority level. On the one hand, I understand that it’s good to prevent playback stutter, but it seems odd that entertainment software would deserve a higher thread priority.

I’m not going to pretend to argue with Joe Duffy on threading, but my understanding is that for general application development (i.e. not Microsoft library development), you’re better off with a spin sleep rather than a spin lock:
while (!proceed) Thread.Sleep(sleepTime);
If you need need need the high performance of a spin lock, you’ll know it; otherwise please don’t lock up my machine.

And for further reading, I highly recommend Joseph Albahari’s e-book, Threading in C#:
http://www.albahari.com/threading/
Free PDF download here:
http://www.albahari.com/threading/threading.pdf

We build systems that require close to real time performance - i.e. if Sleep(10), I’d like to be back in 15-20, not 40-100ms, and if waiting on an event, I’d like to wake up close to the time that event occurred (e.g. network rx is caught by one thread, which swallows buffers acknowledges the message, and sets an event to say data is available to the). Raising the thread priority of threads within the processes which need this performance has performed well, and lowering the process priority of GUIs again improved performance (let’s face it - no point in having a working GUI if you’re losing data because of it…).

Question is, should I be raising the priority of the processes so they all sit at a higher priority than the Windows GUI to start with?

Latest issue is my continuous 6MBytes per sec disk access works most of the time, but sometimes disk IO stalls for more than 2 seconds and my 16MBytes memory buffer gets full…

As a matter of fact, I think that the particular behavior that Scott Allen’s program demonstrates is really a bug in .NET 2.0

What happens is that there is a loop inside the CLR (ThreadNative::StartInner)
that looks like this:

while (!pNewThread-HasThreadState(Thread::TS_FailStarted)
pNewThread-HasThreadState(Thread::TS_Unstarted))
{
__SwitchToThread(0);
}

(from comsynchronizable.cpp in the sscli http://www.microsoft.com/downloads/details.aspx?FamilyId=8C09FD61-3F26-4555-AE17-3121B4F51D4Ddisplaylang=en
)

The loop tries to wait until the thread has actually started before continuing.

The problem is that in the sample there are two threads that are simultaneously executing the code above. This means that we have two normal-priority threads, and one low-priority thread.

The two normal-prio threads are continually calling SwitchToThread which just switches to the other normal-prio thread, which means that the newly creted low-prio thread never gets a chance to run.

This means that the program is stuck until the balance set manager comes in and boosts the prio of the low-prio thread.

Calling SwitchToThread in a loop waiting for another thread to do something is always dangerous.

To fix the problem, there should be a maximum value for the number of times to spin - after the maximum spins the SwitchToThread should fall back to a Sleep(1)

Even if it is dangerous to mess with thread priorities, the .net framework should be able to create low-priority threads without risking long delays.

Another observation is that this loop was not present in .net 1.0 which means that this is also a backwards compatibility problem. The test program would have worked fine on 1.0 but fails miserably on 2.0.

/SG

1 Like