调度程序有时会在启动时忽略分叉进程
Scheduler sometimes ignores forked processes at start
我正在帮助我的一个朋友用C++实现一个软件,该软件使用四个进程,这些进程应该在单核上准并行运行。
四个进程中的三个进程是通过使用fork()
-函数创建的。这些进程由三个信号量(semaOne
、semaTwo
和semaThree
)同步,并在无尽循环中一个接一个地运行"接力赛"(proc1->proc2->proc3->proc1->…)。第四个进程(显然是父进程)是看门狗进程,它执行自己的无尽循环并观察三个子进程。考虑孩子们按预期运作,信号量和同步。
看门狗的实现非常原始,但已经足够了。孩子们用他们的PID向看门狗注册,现在有义务每隔一段时间tick
看门狗,并通过这样做来增加计数器。当调度程序允许看门狗运行时,看门狗本身会checks
子项,并递减每个注册子项的计数器。如果任何计数器达到0状态,则看门狗应该采取行动。
问题是,有时当我们启动软件时,看门狗进程(在一个无休止的循环中调用它的check
-函数)会占据主动,无休止地运行,似乎被调度器忽略了,所以孩子们永远不会运行。经过几次启动软件的尝试,我们很幸运,孩子们成功地开始了他们的"接力赛",然后一切都很好。
正如我所认识到的,调度器在循环模式下工作,应该在所有进程之间分配CPU资源,但这似乎无法正常工作。
如果需要,请询问更多信息!
附言:环境是运行在虚拟盒子中的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;
}
}
我们想要实现的是:即使看门狗/父亲进程在启动时很早就进入了循环,调度器也会给孩子们提供运行的时间段。
感谢您,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 Robins调度器启动Eclipse,并将进程的优先级设置为20:
$ sudo schedtool -R -p 20 -e eclipse
现在,所有将从IDE启动的进程也将使用Round Robin调度器启动。
- 提升进程间message_queue和分叉
- 从执事创建一个分叉进程
- 同时分叉 100 个进程,有时有些进程会变成僵尸
- 使用管道从 STDIN 读取分叉进程时出现问题
- 子进程在分叉和执行后变得失效
- 分叉程序在<defunct>一段时间后给出进程
- 调度程序有时会在启动时忽略分叉进程
- C++ - 分叉进程无法从共享内存读取
- 多个分叉进程无限循环
- 分叉进程的零星堆栈指针分段错误
- 分叉进程之间的随机数是相同的
- Qt是否支持分叉进程?
- 分叉进程不断侦听服务器的端口
- 进程分叉后RAII对象会发生什么
- 多次分叉后无法将消息发送到父进程
- Poco 异步通道不会在分叉进程退出时退出
- 提升说 boost::log 不支持分叉进程。如果记录器直到分叉后才初始化,情况仍然如此吗?
- 断开分叉进程和客户端之间的连接
- 如何在C++中杀死一个分叉进程
- 在c++中正确退出分叉进程