Переносимый способ установки приоритета std::thread в С++ 11

Каков правильный способ в мире сообщений С++ 11 для установки приоритета экземпляра std::thread

Есть ли портативный способ сделать это, который работает, по крайней мере, в средах Windows и POSIX (Linux)?

Или это вопрос получения дескриптора и использования любых собственных вызовов, доступных для конкретной ОС?


person Gerdiner    schedule 19.09.2013    source источник
comment
Этот вопрос (и ответ) по-прежнему актуален и, возможно, всегда будет. Причина того, что для этого не существует специфичного для языка способа, заключается в том, что реализация потоков (если потоки вообще реализованы) зависит от платформы; планирование потоков — это деталь реализации операционной системы. C++ как язык не определяет платформу. Java, с другой стороны, определяет виртуальную машину, которая предоставляет определенные ресурсы (например, многопоточность).   -  person jwm    schedule 16.03.2018
comment
Вы близки к своему ответу, спросив о POSIX, стандартизированном интерфейсе операционной системы. Современная Windows также реализует POSIX (теоретически; я никогда не использовал его), поэтому кодирование в соответствии со спецификацией POSIX должно максимально приблизить вас к переносимости. Приведенные ниже ответы POSIX являются хорошими.   -  person jwm    schedule 16.03.2018


Ответы (5)


Невозможно установить приоритеты потоков через библиотеку C++11. Я не думаю, что это изменится в C++14, и мой хрустальный шар слишком туманен, чтобы комментировать версии после этого.

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

В Win32 BOOL SetThreadPriority(HANDLE hThread,int nPriority)

person Mike Seymour    schedule 19.09.2013
comment
Минус один за нежелание знать, как это делается в винде. Плюс один за знание того, что это нельзя сделать переносимым через С++ 11. - person ; 14.05.2015
comment
Плюс один за нежелание знать, как это делается в Windows. - person Innocent Bystander; 25.08.2018

Моя быстрая реализация...

#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;
};

и вот как я его использую...

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

// set scheduling of created thread
thread::setScheduling(example_thread, SCHED_RR, 2);
person marc    schedule 27.07.2015
comment
на самом деле @MarkusMayr ​​это было очень полезно для демонстрации реальной реализации. другие ответы просто ссылались на функции, но никогда не показывали правильный пример. Это может быть не идиоматично, но я считаю, что это демонстрирует концепцию установки приоритета для определенного потока. По крайней мере - мне помогло. - person Antiokus; 13.03.2016
comment
Обратите внимание, однако, что этот код зависит от поведения конкретной реализации, вызывая native_handle(); стандарт не требует, чтобы эта функция существовала, а если и существует, стандарт не требует, чтобы она имела какое-либо конкретное значение. Все в нем, кроме имени, определяется реализацией. - person Pete Becker; 17.03.2016
comment
Другой полный пример: en.cppreference.com/w/cpp/thread/thread/ родной_дескриптор - person zertyz; 03.09.2019
comment
@PeteBecker Совсем не удивительно, поскольку речь идет о взломе и использовании собственного интерфейса, максимально абстрагированного std::thread. - person Deduplicator; 22.07.2021
comment
@Deduplicator - но удивительно, что стандарт резервирует это имя без какой-либо семантики. К сожалению, мне не удалось убедить комитет в том, что правильный способ сделать это — ничего не делать и предоставить реализации поведение, зависящее от реализации. - person Pete Becker; 22.07.2021
comment
@PeteBecker Им пришлось предоставить какой-то стандартный способ, чтобы получить доступ к основному потоку, иначе каждый и их собака выберут свой собственный, что, кстати, загрязнит пространство для будущей разработки. Они не могли наложить больше ограничений, чем они сделали, потому что это либо ограничило бы соответствующие платформы, либо потребовало бы создания еще одной абстракции только для этого, для которой потребовался бы собственный аварийный люк, и эта дополнительная косвенность ничего бы вам не купила. . - person Deduplicator; 22.07.2021
comment
@Deduplicator -- вы не можете написать переносимый код, использующий эту функцию; вы даже не можете вызвать его в переносимом коде, потому что он не должен существовать. Нет ничего более четко связанного с реализацией, чем это. Использование специфичного для реализации имени указывает на то, что код, в котором оно используется, не является переносимым. - person Pete Becker; 22.07.2021
comment
@PeteBecker Дело в том, что переносимый код (например, шаблоны, обнаруживающие существование и, возможно, возможность вызова) не доставят неудобств, равно как и будущая разработка с использованием мошеннических символов. Кроме того, поскольку этот спасательный люк является общим для других классов, это хорошо известный шаблон, который упрощает поиск кода для конкретной платформы или доказательство его отсутствия. - person Deduplicator; 22.07.2021
comment
Гм, будущие читатели кода, который вызывает native_handle(), не имеют никаких указаний на то, что то, что делается после этого вызова, не является переносимым. Предоставление разработчикам возможности использовать имя из флагов пространства имен разработчика, на которые следует обратить внимание. Даже люди в комитете сделали ошибку, предполагая, что они знали, что они могут сделать с дескриптором, который они вернули, но обнаружили, когда они успешно скомпилировали свой код с другой реализацией библиотеки, что они были неправы. - person Pete Becker; 22.07.2021
comment
Спасибо вам обоим за то, что поделились своими знаниями с этим сообществом и продолжили обсуждение в чате. ???? - person marc; 22.07.2021

Стандартная библиотека C++ не определяет никакого доступа к приоритетам потоков. Чтобы установить атрибуты потока, вы должны использовать native_handle() std::thread и использовать его, например, в системе POSIX с pthread_getschedparam() или pthread_setschedparam(). Я не знаю, есть ли какие-либо предложения по добавлению атрибутов планирования в интерфейс потока.

person Dietmar Kühl    schedule 19.09.2013
comment
Этот ответ более точен, чем другие. - person Mahler; 19.07.2019

В Windows процессы организованы по классу и уровню приоритета. Прочитайте это: Приоритеты планирования, это дает хорошее общее представление о приоритетах потоков и процессов. Вы можете использовать следующие функции для динамического управления приоритетами: GetPriorityClass(), SetPriorityClass(), SetThreadPriority(), GetThreadPriority().

По-видимому, вы также можете использовать native_handle() std::thread с pthread_getschedparam() или pthread_setschedparam() в системе Windows. Посмотрите этот пример, std::thread: Native Handle и обратите внимание на добавлены заголовки!

person Rodrigo Rutsatz    schedule 10.11.2014

Вы можете использовать следующий код для установки приоритетов в Windows

#if defined(_WIN32)
    /* List of possible priority classes:
    https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setpriorityclass
    And respective thread priority numbers:
    https://docs.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

В нашем случае у нас был уровень абстракции, чтобы использовать один и тот же код для создания задач как для Windows, так и для Linux, поэтому tasks::getWinPriorityParameters извлекает значения, ожидаемые от Windows, из нашей абстракции setPriority.

person Spacefish    schedule 21.03.2021