Subj : Re: reliability of setting thread priority To : comp.programming.threads From : David Butenhof Date : Thu Feb 24 2005 04:47 pm gottlobfrege@gmail.com wrote: > How reliable/portable/etc is messing with thread priorities? What do I > mean? Well, let me explain the story: > In particular, similar to the problems of static local initializers > and implementing pthread_once, etc., I want to initialize a critical > section in a thread safe manner. I would use another critical section > to guard the first CS, but that 'begs the question' as they say. :-) I > could use a global named mutex (CreateMutex() under Win32), but that > seems a bit heavy - and if I was going to use a mutex to make a > criticalsection, maybe I should just use a mutex where the CS was going > in the first place. So I'm left with using one or two global > variables, and using atomic get and sets, etc., to manage them. Why not simply initialize all your synchronization statically before the program starts -- or even dynamically in main() before creating any threads? That's always best. If you can't predict static resources, then, yes, one solution is to poll, and one problem with polling in a priority scheduling environment is that you're sending an engraved invitation to priority inversion. > The only problem left is that since I can't use a CS or mutex, the > second thread in must poll to wait for the first thread to finish. > Which is fine, except if the second thread has a higher priority and > thus starves the first thread. So I'm wondering if I can reliably mess > with the thread priorities to handle that problem. This works (I > think) under Windows, but I'm wondering if it would work under other > systems (ie POSIX systems, using pthread_setschedparam, etc. Am I > wrongly assuming 'round-robin' scheduling, etc? How common are various > scheduling rules?). > > And I'm wondering what other problems there might be. ie, yes, I > understand that I am opening myself up to a boat-load of criticism. :-) > In particular, I can imagine memory-visibility/cache-coherency > problems (thus the use of Atomic operations), and also problems if the > 1st thread dies (ie exception, etc) before completing its task, thus > leaving the 2nd thread waiting/polling forever. etc. > > ...Well, anyhow, here's some code. I hope most of the context and > objects make sense. ie 'cs' is a critical section, > ThreadPriorityMaximizer is a class that sets the current threads > priority to max on construction, and back down to whatever it was on > destruction, etc: > > { > ThreadPriorityMaximizer maximizer; > > if (!AtomicExchange(&entry, true)) > { > // we are in, and at max priority > > // init our critical section: > cs.Init(); > AtomicExchange(&initted, true); > } > else > { > // we are not in, but _still_ at max priority > // better lower our priority before we just sit and spin at max! > maximizer.Revert(); > > while (!AtomicRead(&initted)) > { > Sleep(1); > } > } > } > > well, what do you think? It appears to me that you're essentially trying to emulate "priority ceiling" mutexes, to control priority inversion, without the standard POSIX mutex attributes. That's fine, if you really need it. Generally, unless you've got a "hard realtime" application that interacts with physical devices that are time-critical, you're better off simply skipping the scheduling stuff entirely. (The resulting application will be simpler and generally faster, because the scheduling management adds overhead.) If an implementation supports the _PTHREAD_PRIO_PROTECT option, you can create a mutex attributes object and use pthread_mutexattr_setprotocol(attr, PTHREAD_PRIO_PROTECT) to select priority ceiling, and pthread_mutexattr_setprioceiling(attr, ) to set the ceiling value. Without the option, you can emulate priority ceiling much as suggested by your code -- though you've provided too little detail to determine whether you've done it "right". In general, setting "maximum" as the ceiling is a bad idea, because you're probably precluding more executable threads than necessary. (There may be no alternative if your high priority thread runs at that priority; but this is why THAT'S usually a bad idea.) Also, you don't show the implementation of your Revert method; but the obvious POSIX implementation would be pthread_setschedparams(), which will always bump the thread to the back of its scheduling queue. The pthread_setschedprio() function was invented for this specific purpose, and doesn't do that "bump" when lowering priority. -- Dave Butenhof, David.Butenhof@hp.com HP Utility Pricing software, POSIX thread consultant Manageability Solutions Lab (MSL), Hewlett-Packard Company 110 Spit Brook Road, ZK2/3-Q18, Nashua, NH 03062 .