Планировщик иногда игнорирует разветвленные процессы при запуске - PullRequest
0 голосов
/ 26 января 2019

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

Три из четырех процессов создаются с использованиемfork() -функция.Эти процессы синхронизируются тремя семафорами (semaOne, semaTwo и semaThree) и запускают "эстафету" один за другим в бесконечном цикле (proc1 -> proc2 -> proc3 -> proc1 -> ...).Четвертый процесс (очевидно, родительский) - это сторожевой процесс, который выполняет свой собственный бесконечный цикл и наблюдает за тремя дочерними процессами.Представьте, что дети функционируют так, как ожидалось, семафоры и синхронизация тоже.

Реализация сторожевого таймера очень примитивна, но достаточна.Дети регистрируют себя в сторожевом таймере с помощью своего PID и теперь обязаны время от времени tick сторожевым таймером увеличивать счетчик.Сам сторожевой таймер, когда он разрешен планировщиком, запускает checks записи дочерних элементов и уменьшает счетчик каждого зарегистрированного дочернего элемента.Если какой-либо счетчик достигает состояния 0, сторожевой таймер должен принять меры.

Проблема заключается в том, что иногда, когда мы запускаем программное обеспечение, сторожевой таймер обрабатывает, где в бесконечном цикле это check -функцияназывается, захватывает инициативу и работает бесконечно и, кажется, планировщик игнорирует ее, поэтому дети никогда не бегут.После нескольких попыток запустить программное обеспечение нам повезло, что детям удалось запустить свою «эстафету», и тогда все работает нормально.

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

Пожалуйста, запросите дополнительную информацию, если это необходимо!

PS Среда, в которой работает Ubuntu Linux 16.04, работает вВиртуальный ящик

Как вы можете видеть, я уже пытался уменьшить приоритет родительского процесса в надежде, что это может повлиять на планировщик, и призвать его предоставить временной интервал для детей, но этого никогда не происходит..

// main.cpp

// Shared memory allocation and instantiation of semaphores happen here
// This part of the code relies on a simple framework that was given
// by the lecturer. It works as expected and is of no concern in the scope
// of the actual problem.

CWatchdog myWD;
pthread_t proc1 = 0;
pthread_t proc2 = 0;
pthread_t proc3 = 0;

int main(void) {
    pthread_t PID;

    myWD.init();

    PID = fork();

    if (PID == 0) {
        // proc1
        proc1 = getpid();

        myWD.register(proc1);

        while (true) {
            semaOne->take();

            std::cout << "[PROC 1] here" << std::endl;
            // per1form proc1 task here and TICK the watchdog
            myWD.tick(proc1);
            usleep(2000000);

            semaTwo->give();
        }

    } else if (fork() == 0) {
        // proc2
        proc2 = getpid();

        myWD.register(proc2);

        while (true) {
            semaTwo->take();

            std::cout << "[PROC 2] here" << std::endl;
            // perform proc2 task here and TICK the watchdog
            myWD.tick(proc2);
            usleep(2000000);

            semaThree->give();
        }
    } else if (fork() == 0) {
        // proc3
        proc3 = getpid();

        myWD.register(proc3);

        while (true) {
            semaThree->take();

            std::cout << "[PROC 3] here" << std::endl;
            // perform proc3 task here and TICK the watchdog
            myWD.tick(proc3);
            usleep(2000000);

            semaOne->give();
        }
    } else {
        pthread_t wdProcID = getpid();
        int myPrio = 0;

        myPrio = getpriority(PRIO_PROCESS, 0);
        // 0 for current process!
        std::cout << "[WD] PID, priority (old) " << wdProcID << ", " << myPrio << std::endl;
        setpriority(PRIO_PROCESS, 0, -20);

        while (true) {
            std::cout << "[WD] here" << std::endl;
            // perform watchdog task here: CHECK the children
            myWD.check();
            usleep(50000);
        }
        return 0;
    }
}

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

1 Ответ

0 голосов
/ 27 января 2019

Спасибо, 2785528, за идею проверить тип планировщика!

Я нашел решение, и теперь все работает, как ожидалось.

Следующие инструкции применимы для моей системы разработки Ubuntu 16.04, но также и для других дистрибутивов.

В оболочке Linux политику планирования любого процесса можно отобразить с помощью инструмента chrt. Параметр -p передает PID процесса, политику планирования которого вы хотите отобразить.

Следующий вывод для Firefox, который в настоящее время работает в моей системе:

$ chrt -p 19580
pid 19580's current scheduling policy: SCHED_OTHER
pid 19580's current scheduling priority: 0

"SCHED_NORMAL / SCHED_OTHER Это политика по умолчанию и для средней программы с некоторым взаимодействием. Осуществляет вытеснение других процессов." (от http://manpages.ubuntu.com/manpages/xenial/man8/schedtool.8.html)

Политика планирования по умолчанию не Rount-Robin! Таким образом, чтобы запустить любое программное обеспечение с планировщиком Round-Robin, оно должно быть явно выбрано. В моем Ubuntu 16.04 есть инструмент под названием schedtool, который позволяет вам выбрать любой планировщик, доступный в вашей системе.

schedtool, если он еще не установлен, может быть легко установлен:

$ sudo apt-get install schedtool

Теперь, выполнив schedtool без каких-либо параметров, можно отобразить справку инструмента. Вот выдержка со списком политик планирования, которые инструмент может обработать:

set scheduling policies:
    -N                    for SCHED_NORMAL
    -F -p PRIO            for SCHED_FIFO       only as root
    -R -p PRIO            for SCHED_RR         only as root
    -B                    for SCHED_BATCH
    -I -p PRIO            for SCHED_ISO
    -D                    for SCHED_IDLEPRIO

Поскольку я хотел использовать Round-Robin для нашего программного обеспечения, которое я запускаю из Eclipse IDE, я использовал schedtool, чтобы запустить Eclipse с планировщиком Round-Robin и установить приоритет процесса на 20:

$ sudo schedtool -R -p 20 -e eclipse

Теперь все процессы, которые будут запускаться из IDE, также будут запускаться с помощью планировщика Round-Robin.

...