Почему pthread_barrier_wait не учитывает приоритеты потоков? - PullRequest
0 голосов
/ 16 мая 2018

Я использую барьеры для синхронизации двух потоков, которые будут выполнять task_1 и task_2 соответственно.

После их синхронизации мне бы хотелось, чтобы задача с более высоким приоритетом начала выполняться перед задачами с более низким приоритетом.

Я с удивлением заметил, что, хотя task_2 имеет более низкий приоритет, чем task_1 , иногда task_2 начинает выполняться до task_1 .

#include <pthread.h>
#include <sched.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>

#define MAX_PRIORITY 99
#define MIN_PRIORITY 1

pthread_t threads[2];
pthread_barrier_t barrier;

void set_priority(int priority, int t_id){
    int policy = SCHED_FIFO;
    struct sched_param param;

    param.sched_priority = priority;

    pthread_attr_t attr;
    pthread_attr_init (&attr);

    pthread_setschedparam(pthread_self(), policy, &param);

    pthread_getschedparam(pthread_self(), &policy, &param);
}

int set_core(int core_id) {
    int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
    if (core_id < 0 || core_id >= num_cores)
        return EINVAL;

    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(core_id, &cpuset);

    pthread_t current_thread = pthread_self();
    return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
}
void create_task(int task_number, void *task) {
    int rc = pthread_create(&threads[task_number - 1], NULL, task, NULL);
    if(rc != 0) {
        printf("pthread_create(%d) error %d\n", task_number - 1, rc);
        pthread_exit(0) ;
    }
}

void schedule_task(int task_number, int priority) {
    set_core(2); //running tasks only in 2nd processor core
    set_priority(priority, task_number);
}

void start_task_1() {
    printf("Task 1 Started \n");
    sleep(1); //do task 1
    printf("Task 1 Endeded\n");
}

void start_task_2() {
    printf("Task 2 Started \n");
    sleep(1); //do task 2
    printf("Task 2 Endeded\n");
}

void task_1(void *thread_param) {
    schedule_task(1, MAX_PRIORITY);
    pthread_barrier_wait(&barrier);

    start_task_1();

    pthread_exit(NULL);
}

void task_2(void *thread_param) {
    schedule_task(2, MIN_PRIORITY);
    pthread_barrier_wait(&barrier);

    start_task_2();

    pthread_exit(NULL);
}

int main() {
    pthread_barrier_init(&barrier, NULL, 2);

    create_task(1, task_1);
    create_task(2, task_2);

    for (int i = 0; i < 2; i++) {
        pthread_join(threads[i], NULL);
    } 

    pthread_barrier_destroy(&barrier);
}

Это ожидаемое поведение в потоках POSIX?Что я могу сделать, чтобы task_1 всегда запускался раньше, чем task_2 ?

Я выполняю программу от имени пользователя root и обеспечил установку приоритетов задачсоответственно.

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Вы создаете два разных потока и ограничиваете их разделением ядер. Это правда, что один из них имеет более высокий приоритет, чем другой, но оба являются потоками SCHED_FIFO, что, вероятно, делает каждый из них задачей с наивысшим приоритетом в соответствующем ядре (по крайней мере, среди задач пользовательского уровня). Поскольку каждое ядро ​​имеет отдельную очередь задач, которую можно запустить, политика планирования будет влиять только на сравнение задач одного и того же ядра.

Таким образом, для всех практических целей две задачи фактически имеют одинаковый эффективный приоритет. Следовательно, нет оснований ожидать, что задача 1 начнет выполняться раньше, чем задача 2 после ожидания барьера. Если вы хотите применить это (хотя они по-прежнему работают на разных ядрах), вам нужно будет использовать некоторую другую переменную общего доступа, чтобы задача 1 сообщила задаче 2, что все в порядке. Это может быть семафор, флаг, защищенный мьютексом, или на большинстве архитектур, просто занятый цикл для атомарно обновленного целого флага.

0 голосов
/ 16 мая 2018

Планирование зависит от алгоритма планирования, используемого в ОС. Вы пытаетесь использовать FIFO, который согласно manpage доступен только при включенном расписании в реальном времени.

   Various "real-time" policies are also supported, for special time-
   critical applications that need precise control over the way in which
   runnable threads are selected for execution.  For the rules governing
   when a process may use these policies, see sched(7).  The real-time
   policies that may be specified in policy are:

        SCHED_FIFO    a first-in, first-out policy; and

        SCHED_RR      a round-robin policy.

Если вы используете Linux, алгоритмы планирования выбираются во время компиляции ядра, но не уверены, что их можно изменить во время загрузки или динамически.

...