调度程序有时会在启动时忽略分叉的进程

时间:2019-01-26 14:15:05

标签: c++ synchronization fork scheduler

我正在帮助我的一个朋友用C ++实现软件,该软件利用了应该在单核上准并行运行的四个进程。

通过使用fork()函数创建四个进程中的三个。这些过程由三个信号量(semaOnesemaTwosemaThree进行同步,并在无穷循环(proc1-> proc2-> proc3- > proc1-> ...)。第四个进程(显然是父进程)是看门狗进程,它执行自己的无限循环并观察三个子进程。 考虑孩子的功能正常,信号量和同步。

看门狗实现非常原始,但是足够了。孩子们使用其PID向看门狗注册自己,现在不得不不时tick一次看门狗,并以此来增加计数器。当调度程序允许其运行时,看门狗本身会checks子项的输入并减少每个已注册子项的计数器。如果任何计数器的状态为0,则看门狗应该采取措施。

问题是,有时当我们启动软件时,看门狗进程会在无休止的循环中调用check函数,从而获得主动权并无限地运行,并且似乎被调度程序忽略,这样孩子们永远不会跑。经过几次尝试启动该软件,我们很幸运,孩子们设法开始了他们的“接力赛”,然后一切正常。

据我所知,调度程序正在循环模式下工作,应该在所有进程之间分配CPU资源,但这似乎无法正常工作。

请根据需要询问其他信息!

P.S。环境是在Virtual Box中运行的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 :(得分:0)

谢谢2785528,这个想法可以检查调度程序类型!

我找到了解决方案,现在一切都按预期运行。

以下说明适用于我的开发系统Ubuntu 16.04,也适用于其他发行版。

在Linux Shell中,可以使用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

由于我需要从Eclipse IDE开始运行的Round-Robin软件,因此我使用schedtool使用Round-Robin调度程序启动Eclipse,并将进程的优先级设置为20:

$ sudo schedtool -R -p 20 -e eclipse

现在,将从IDE启动的所有进程也将通过Round-Robin Scheduler启动。