When using std::async, what is the best way to set priority? I realize this is platform dependent, but with a posix compliant operating system, would this work?
// Launch task with priority 8
auto future = std::async(std::launch::async, // async policy required
[] ()
{
pthread_setschedprio(pthread_self(), 8);
// do work
});
I've found answers about std::thread, but not for std::async.
Edit. In my case I am on a QNX operating system. So I believe setting the priority like I've done above is valid. However, it does seem like there are valid concerns raised about whether or not the priority will persist after the async task is complete (depending how async is implemented).
Edit2 Potential options seem to be...
- Leverage std::thread (perhaps with a thread pool) to keep explicitly managed threads at a given priority
- Justify in my situation that setting the priority is not necessary.
- Create an RAII class to change priority back to the original at the end of the async launched lambda.
CodePudding user response:
I suspect your design is a bad idea.
std::async
is required to behave as-if it was a new std::thread
. But it doesn't have to be on a new pthread. The implementation is free to (and probably should) have a set of underlying threads that it recycles for std::async
-- just clean up thread_local
storage and handle stuff like set_value_at_thread_exit
it would work (under the standard).
Accessing the underlying pthread and messing with its priority, in that case, might impact later async tasks.
I cannot state certainly this would happen, but I found on at least one system that there is an underlying thread pool -- the symptom was that after a certain number of std::async
s new ones waited to be scheduled for old ones to finish. On a low-core system, this caused a deadlock in some insufficiently paranoid code (the dependency chain of waiting for other threads got larger than the thread pool size, so the last task wasn't scheduled). That deadlock shouldn't happen under the standard; but it is evidence that platforms do use thread pools for async.
Consider making your own thread pool on top of std::thread
, and implementing something async
-like on top of it with a priority. If you are keeping std::thread
s around and managing the priority yourself that is less likely to cause problems.
For std::thread
, you can get its native_handle
, which on your system is probably a pthread handle.
CodePudding user response:
For all intents and purposes it will work. Be cautious about thread pools. I think std::launch::async
doesn't use thread pools because it guarantees immediate launches and this would also interfere with any std::promises
that use set_value_at_thread_exit
. But std::launch::async | std::launch::deferred
may use a thread pool so this priority will affect future async calls if you are not careful.
A fix would be pretty simple: Just set up a destructor that changes the priority back to the original.
However, note that you are misusing the pthread interface. At least on Linux you will get an EINVAL error as noted here: pthread_setschedprio() fails with "EINVAL" Basically, priority is not supported for normal scheduling. You would have to switch to real-time scheduling via FIFO or round-robin first.
What you are probably thinking of is the nice
value. But that is per-process as far as I know. What you can do is lower the thread priority by changing the policy to SCHED_BATCH
or SCHED_IDLE
:
const sched_param param{};
pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m);
Be very cautious about priority inversion when using these. Batch and idle scheduling lower the priority severely more than a simple nice
value.