81

What is the correct way in the post C++11 world for setting the priority of an instance of std::thread

Is there a portable way of doing this that works at least in Windows and POSIX (Linux) environments?

Or is it a matter of getting a handle and using whatever native calls are available for the particular OS?

Gerdiner
  • 1,435
  • 3
  • 15
  • 19
  • 2
    This question (and answer) is still relevant, and possibly always will be. The reason that there is no language-specific way to do this is that the implementation of threading (if threads are implemented at all) is platform-specific; the scheduling of threads is a detail of the operating system implementation. C++ as a language does not define a platform. Java, on the other hand, does define a virtual machine that provides certain resource (such as threading). – jwm Mar 15 '18 at 22:23
  • 1
    You are close to your answer by asking about POSIX, which is a standardized operating system interface. Modern Windows also implements POSIX (in theory; I've never used it), so coding to the POSIX specification should get you as close as possible to portable. The POSIX answers below are good ones. – jwm Mar 15 '18 at 22:25
  • @jwm: Totally fatuous answer. Java did it. POSIX did it. .net did it. There is absolutely no reason why the C++ standards committee couldn't also do it. C++ does define a platform. Threading is a feature of the C++ platform. Literally hundreds of pages of the standard deal with threading issues. The reason why the C++ standards committee didn't include thread priority... a long sad answer that has more to do with politics than being able to do it. It is most definitely not because threads are platform specific. – Robin Davies Jul 27 '21 at 03:16
  • 2
    I'm not responsible for what the C++ standards committee did or did not do. I disagree that C++ defines a platform; that is one of the fundamental differences between a virtual machine and a language. And yes, threading **is** platform-specific; the C++ language just defines the very thinnest of APIs that all platforms can support. – jwm Jul 27 '21 at 03:22

6 Answers6

73

There's no way to set thread priorities via the C++11 library. I don't think this is going to change in C++14, and my crystal ball is too hazy to comment on versions after that.

In POSIX, pthread_setschedparam(thread.native_handle(), policy, {priority});

In Win32 BOOL SetThreadPriority(HANDLE hThread,int nPriority)

Iter Ator
  • 8,226
  • 20
  • 73
  • 164
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
45

My quick implementation...

#include <thread>
#include <pthread.h>
#include <iostream>
#include <cstring>

class thread : public std::thread
{
  public:
    thread() {}
    static void setScheduling(std::thread &th, int policy, int priority) {
        sch_params.sched_priority = priority;
        if(pthread_setschedparam(th.native_handle(), policy, &sch_params)) {
            std::cerr << "Failed to set Thread scheduling : " << std::strerror(errno) << std::endl;
        }
    }
  private:
    sched_param sch_params;
};

and this is how I use it...

// create thread
std::thread example_thread(example_function);

// set scheduling of created thread
thread::setScheduling(example_thread, SCHED_RR, 2);
marc
  • 1,207
  • 11
  • 16
  • 16
    actually @MarkusMayr this was pretty useful in showing a real implementation. the other answers just referred the functions but never showed a proper example. It might not be idiomatic, but I believe it demonstrates the concept of setting a priority for a particular thread. At the very least - it helped me. – Antiokus Mar 13 '16 at 15:31
  • 1
    Note, however, that this code relies on implementation-specific behavior by calling `native_handle()`; the standard does not require that function to exist, and if it does, the standard does not require it to have any particular meaning. Everything about it except its name is implementation defined. – Pete Becker Mar 17 '16 at 14:25
  • 3
    Another complete example: https://en.cppreference.com/w/cpp/thread/thread/native_handle – zertyz Sep 03 '19 at 15:37
  • 1
    @PeteBecker Not surprising at all, as it is all about breaking into and using the native interface abstracted as possible by `std::thread`. – Deduplicator Jul 22 '21 at 13:05
  • @Deduplicator -- but it **is** surprising that the standard reserves that name with no semantics whatsoever. Unfortunately, I couldn't convince the committee that the right way to do that is to do nothing, and leave it to the implementation to provide implementation-specific behavior. – Pete Becker Jul 22 '21 at 13:07
  • @PeteBecker They had to provide *some standard way* for getting a hand on the underlying thread, or everybody and their dog would choose their own, incidentally tainting the space for future development. They couldn't give it any more constraints than they did, because that would either limit conforming platforms, or necessitate building yet another abstraction just for this, which would need its own escape hatch, and that additional indirection wouldn't buy you anything really. – Deduplicator Jul 22 '21 at 15:10
  • @Deduplicator -- there's **no portable code** that you can write that uses this function; you can't even **call it** in portable code, because it doesn't have to exist. There's nothing at all that's more clearly implementation-specific than that. Using an implementation-specific name would point out that code that uses it is not portable. – Pete Becker Jul 22 '21 at 15:33
  • @PeteBecker The point is that portable code (for example templates detecting existence and maybe ability to invoke) won't be inconvenienced, nor will future development by rogue symbols. Also, especially as this escape-hatch is shared across other classes, it is a well-known pattern and eases search for that platform-specific code, or proving its absence. – Deduplicator Jul 22 '21 at 15:39
  • Um, future **readers** of code that calls `native_handle()` don't have any indication that what's done after that call is not portable. Leaving it to implementors to use a name from the implementer's namespace flags that there is something here to watch out for. Even folks on the committee have made the mistake of assuming that they knew what they could do with the handle that they got back, but discovered, when they successfully compiled their code with a different library implemenation, that they were wrong. – Pete Becker Jul 22 '21 at 15:49
18

The standard C++ library doesn't define any access to thread priorities. To set thread attributes you'd use the std::thread's native_handle() and use it, e.g., on a POSIX system with pthread_getschedparam() or pthread_setschedparam(). I don't know if there are any proposals to add scheduling attributes to the thread interface.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
10

In Windows processes are organized in class and level priority. Read this: Scheduling Priorities, it gives a good overall knowledge about thread and process priority. You can use the following functions to control the priorities even dynamically: GetPriorityClass(), SetPriorityClass(), SetThreadPriority(), GetThreadPriority().

Apperantly you can also use std::thread's native_handle() with pthread_getschedparam() or pthread_setschedparam() on a windows system. Check this example, std::thread: Native Handle and pay attention to the headers added!

Rodrigo Rutsatz
  • 285
  • 5
  • 11
1

For lowering priority of the current thread, I use:

namespace
{
#ifdef WIN32
    auto lower_my_priority() -> bool
    {
        int priority { GetThreadPriority(GetCurrentThread()) };
        return priority != THREAD_PRIORITY_ERROR_RETURN 
            && priority > THREAD_PRIORITY_IDLE
            && SetThreadPriority(
                GetCurrentThread(),
                priority > THREAD_PRIORITY_HIGHEST
                    ? THREAD_PRIORITY_HIGHEST
                    : priority > THREAD_PRIORITY_ABOVE_NORMAL
                    ? THREAD_PRIORITY_ABOVE_NORMAL
                    : priority > THREAD_PRIORITY_NORMAL
                    ? THREAD_PRIORITY_NORMAL
                    : priority > THREAD_PRIORITY_BELOW_NORMAL
                    ? THREAD_PRIORITY_BELOW_NORMAL
                    : priority > THREAD_PRIORITY_LOWEST
                    ? THREAD_PRIORITY_LOWEST
                    : THREAD_PRIORITY_IDLE)
            != 0;
    }
#else
    auto lower_my_priority() -> bool
    {
        int policy;
        sched_param params;
        if (pthread_getschedparam(
            pthread_self(), &policy, &params) == 0)
        {
            int const min_value{ sched_get_priority_min(policy) };
            if (min_value != -1)
            {
                if (params.sched_priority > min_value)
                {
                    --params.sched_priority;
                    if (pthread_setschedparam(pthread_self(), policy, &params) != -1)
                    {
                        return true;
                    }
                }
            }
        }

        return false;
    }
#endif
}

You can, of course write the equivalent code for raising priority

mheyman
  • 4,211
  • 37
  • 34
0

You can use the following code to set the priorities in Windows

#if defined(_WIN32)
    /* List of possible priority classes:
    https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setpriorityclass
    And respective thread priority numbers:
    https://learn.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
    */
    DWORD dwPriorityClass = 0;
    int nPriorityNumber = 0;
    tasks::getWinPriorityParameters(setPriority, dwPriorityClass, nPriorityNumber);
    int result = SetPriorityClass(
            reinterpret_cast<HANDLE>(mainThread.native_handle()),
            dwPriorityClass);
    if(result != 0) {
          std::cerr << "Setting priority class failed with " << GetLastError() << std::endl;
    }
    result = SetThreadPriority(
            reinterpret_cast<HANDLE>(mainThread.native_handle()),
            nPriorityNumber);
    if(result != 0) {
          std::cerr << "Setting priority number failed with " << GetLastError() << std::endl;
    }
#endif

In our case, we had an abstraction layer to use the same code for both Windows and Linux task creation, so the tasks::getWinPriorityParameters extracts the values expected from Windows from our setPriority abstraction.

Spacefish
  • 305
  • 4
  • 11