C Pthread Priority: Невозможно получить ожидаемое поведение - PullRequest
0 голосов
/ 08 ноября 2019

Здесь я пытаюсь создать два потока, назначить им приоритеты / политики и получить ожидаемое поведение.

Ожидаемое поведение: поток с наивысшим приоритетом (в данном случае поток1) должен выполняться всегда первым,Что я вижу: вывод потока смешивается, что означает, что приоритет не соблюдается.

Вот код:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>


void *thread_func1 ();
void *thread_func2 ();

int main (){

    pthread_t thread1, thread2;
    pthread_attr_t attr1, attr2; 

    struct sched_param param1, param2;

    int thread1_prio = 70;
    int thread2_prio = 69;

    int policy1, policy2;

    policy1 = SCHED_RR;
    policy2 = SCHED_RR;

    pthread_attr_init(&attr1);
    pthread_attr_init(&attr2);


    param1.sched_priority = thread1_prio;
    param2.sched_priority = thread2_prio;

    pthread_attr_setschedparam(&attr1, &param1);
    pthread_attr_setschedparam(&attr2, &param2);

    pthread_attr_setschedpolicy(&attr1, policy1);
    pthread_attr_setschedpolicy(&attr2, policy2);   

    pthread_attr_getschedparam(&attr1, &param1);
    pthread_attr_getschedparam(&attr2, &param2);

    pthread_attr_getschedpolicy(&attr1, &policy1);
    pthread_attr_getschedpolicy(&attr2, &policy2);  

    pthread_create(&thread1, &attr1, thread_func1, NULL);
    pthread_create(&thread2, &attr2, thread_func2, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);


    return 0;
}

void *thread_func1 (void *var){

    for (int i = 0; i<5; i++){
        printf("Thread: 1\n");
    }

    return 0;
}

void *thread_func2 (void *var){

    for (int i=0; i<5; i++){
        printf("Thread: 2\n");
    }
    return 0;
}
  • Я также пытался использовать pthread_setschedprio, все еще не смог получить ожидаемый результат.
  • Выполнение программы как root

До публикации этого вопроса я пытался следить за многими постами / примерами, но в итоге все больше запутался. Любая помощь приветствуется.

Редактировать: Разве это не был настоящий вопрос? Я имею в виду, пожалуйста, поправьте меня, если это было глупо, чтобы опубликовать это и заслуживают отрицательных голосов, как некоторые из вас уже проголосовали против?

Ответы [ 2 ]

2 голосов
/ 08 ноября 2019

Ожидаемое поведение: поток с наивысшим приоритетом (в данном случае поток 1) должен выполняться всегда первым.

В целом, Linux так не работает. Основной дизайн вращается вокруг разделения времени, когда приоритет задачи влияет на процент времени процессора, который получает задача, и не влияет на задержку или прерывание. Он просто не предназначен для выполнения «задачи с наивысшим приоритетом, которая может выполняться, запускается (и прерывает задачи с более низким приоритетом)», как вы хотите.

Кроме того:

  • Приоритеты pthread полностью нарушены и не поддерживаются практически во всем (кроме политики планирования в реальном времени, которая не должна использоваться обычным программным обеспечением и, вероятно, не должна использоваться, если у вас также есть жесткие требования в реальном времени).

  • nice() также не работает, поскольку он воздействует на отдельные потоки, а не на все потоки, принадлежащие всему процессу, как это должно быть. Это нарушение означает, что вы можете (вроде) использовать nice() вместо приоритетов pthread, если вы храбры.

  • поведение предела "приоритет" / хороший - (или припо крайней мере, я не проверял, если это было недавно исправлено) также сломан;в том, что независимо от того, какой лимит вы можете, вы можете только уменьшить приоритет своей задачи и не можете увеличить его обратно до предела. Это полностью нарушает несколько общих схем (например, «рабочий поток / потоки получают задание из очереди, затем настраивает его приоритет в соответствии с этим заданием» и «поток предварительно генерирует объекты для будущего использования, а затем помещает их в пул и настраивает его приоритет наудовлетворить спрос (в зависимости от того, насколько полный / пустой пул) ").

Конечным результатом является то, что (без особых хлопот - например, слой многопоточности пользовательского пространства поверх ядраразбитый беспорядок) вы фактически оставили возможность эмулировать мизерную «2-приоритетную» систему, используя «SCHED_RR» (плюс nice() для незначительной / незначительной корректировки) в качестве высокого / среднего приоритета и «SCHED_IDLE» в качестве низкого приоритета.

В основном;вероятно, лучше забыть о написании программного обеспечения, которое правильно использует приоритеты потоков (оно слишком трудное, не переносимое и дает лишь часть преимуществ, которые оно должно). Конечно, это также основная проблема (потому что большинство программного обеспечения не использует приоритеты потоков, поэтому разработчикам ядра не очень важно понимать, как должен работать планировщик и не фиксировать приоритет потоков, поэтому большинство программ не использует потокприоритеты - это самосохраняющаяся петля обратной связи идиотизма, которая сохраняется уже 3 десятилетия).

1 голос
/ 08 ноября 2019

Я украсил вашу программу для проверки на наличие ошибок, и эта строка:

pthread_attr_setschedparam(&attr1, &param1);

Последовательно завершалась ошибка с EINVAL, root или нет. Быстрая проверка руководства показала, что перед этим вы должны:

pthread_attr_setinheritsched(&attr1, PTHREAD_EXPLICIT_SCHED);

Это все еще не совсем исправляет, немного более непонятно, что вы должны установить политику перед приоритетом, поэтому порядок: setinheritsched, setschedpolicy, setschedparam.

Делает ли ваша конкретная posix-OS что-нибудь полезное с параметрами планирования - кто-нибудь догадывается, но, по крайней мере, это дает ему шанс на победу.

Несколькопримечания:

  1. Для правильного наблюдения вам необходимо привязать потоки к одному процессору.
  2. Вам нужно либо сделать приоритет main () выше, чем любого потока,или заставьте нити начинаться у барьера, чтобы вы могли одновременно их выпустить. В противном случае ваш первый поток мог бы завершиться до завершения второго.
  3. Атрибуты потока Posix - беспорядок, и вы действительно хотите проверить их на наличие сбоев. Обычно я оборачиваю их в макрос типа assert.

С этими исправлениями и улучшениями на моем Ubuntu 16 ваша программа работает должным образом.

...