【发布时间】:2021-01-11 15:05:02
【问题描述】:
TL;DR
在多处理器/多核引擎上,可以在多个执行单元上调度多个 RT SCHED_FIFO 线程。因此优先级为 60 的线程和优先级为 40 的线程可以同时运行在 2 个不同的内核上。
这可能违反直觉,尤其是在模拟嵌入式系统时(通常像今天一样)在单核处理器上运行并依赖严格的优先级执行。
请参阅此帖子中的my other answer 了解摘要
原始问题描述
即使使用非常简单的代码来让 Linux 使用调度策略 SCHED_FIFO 尊重我的线程的优先级,我也遇到了困难。
- 请参阅问题末尾的 MCVE。
- 在答案中查看修改后的 MCVE
这种情况来自于需要在 Linux PC 下模拟嵌入式代码以执行集成测试
fifo 优先级10 的main 线程将启动线程divisor 和ratio。
divisor 线程应该得到priority 2,这样带有priority 1 的ratio 线程在b 得到一个合适的值之前不会评估a/b(这只是MCVE 的一个完全假设的场景,而不是真实的带有信号量或条件变量的生活案例)。
潜在的先决条件:您需要是 root 或更好地setcap 程序,以便可以更改调度策略和优先级
sudo setcap cap_sys_nice+ep main
johndoe@VirtualBox:~/Code/gdb_sched_fifo$ getcap main
main = cap_sys_nice+ep
-
第一个实验是在 2 个 vCPU 的 Virtualbox 环境下进行的(gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0, GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git),代码行为差不多
OK在正常执行下但NOK在 GDB 下。 -
本机 Ubuntu 20.04 上的其他实验显示了非常频繁的
NOK行为,即使在 I3-1005 2C/4T (gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0、GNU gdb (Ubuntu 9.1-0ubuntu1) 9.1 的正常执行中) )
基本编译:
johndoe@VirtualBox:~/Code/gdb_sched_fifo$ g++ main.cc -o main -pthread
正常执行有时可以,有时如果没有 root 或没有 setcap 则不行
johndoe@VirtualBox:~/Code/gdb_sched_fifo$ ./main
Problem with setschedparam: Operation not permitted(1) <<-- err msg if no root or setcap
Result: 0.333333 or Result: Inf <<-- 1/3 or div by 0
正常执行正常(例如使用 setcap )
johndoe@VirtualBox:~/Code/gdb_sched_fifo$ ./main
Result: 0.333333
现在如果你想调试这个程序,你会再次收到错误消息。
(gdb) run
Starting program: /home/johndoe/Code/gdb_sched_fifo/main
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7f929a6a9700 (LWP 2633)]
Problem with setschedparam: Operation not permitted(1) <<--- ERROR MSG
Result: inf <<--- DIV BY 0
[New Thread 0x7f9299ea8700 (LWP 2634)]
[Thread 0x7f929a6a9700 (LWP 2633) exited]
[Thread 0x7f9299ea8700 (LWP 2634) exited]
[Inferior 1 (process 2629) exited normally]
这在这个问题gdb appears to ignore executable capabilities 中有解释(几乎所有答案都可能是相关的)。
所以在我的情况下,我做到了
sudo setcap cap_sys_nice+ep /usr/bin/gdb- 用
set startup-with-shell off创建一个~/.gdbinit
结果我得到了:
(gdb) run
Starting program: /home/johndoe/Code/gdb_sched_fifo/main
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff6e85700 (LWP 2691)]
Result: inf <<-- NO ERR MSG but DIV BY 0
[New Thread 0x7ffff6684700 (LWP 2692)]
[Thread 0x7ffff6e85700 (LWP 2691) exited]
[Thread 0x7ffff6684700 (LWP 2692) exited]
[Inferior 1 (process 2687) exited normally]
(gdb)
结论和问题
- 我认为唯一的问题来自 GDB
- 在另一个(非虚拟)目标上的测试在正常执行下显示出更差的结果
我看到其他与 RT SCHED_FIFO 相关的问题没有得到尊重,但我发现答案没有或不明确的结论。我的 MCVE 也更小,潜在的副作用更少
Linux SCHED_FIFO not respecting thread priorities
SCHED_FIFO higher priority thread is getting preempted by the SCHED_FIFO lower priority thread?
评论带来了一些答案,但我仍然不相信......(......它应该像这样工作)
MCVE:
#include <iostream>
#include <thread>
#include <cstring>
double a = 1.0F;
double b = 0.0F;
void ratio(void)
{
struct sched_param param;
param.sched_priority = 1;
int ret = pthread_setschedparam(pthread_self(),SCHED_FIFO,¶m);
if ( 0 != ret )
std::cout << "Problem with setschedparam: " << std::strerror(errno) << '(' << errno << ')' << "\n" << std::flush;
std::cout << "Result: " << a/b << "\n" << std::flush;
}
void divisor(void)
{
struct sched_param param;
param.sched_priority = 2;
pthread_setschedparam(pthread_self(),SCHED_FIFO,¶m);
b = 3.0F;
std::this_thread::sleep_for(std::chrono::milliseconds(2000u));
}
int main(int argc, char * argv[])
{
struct sched_param param;
param.sched_priority = 10;
pthread_setschedparam(pthread_self(),SCHED_FIFO,¶m);
std::thread thr_ratio(ratio);
std::thread thr_divisor(divisor);
thr_ratio.join();
thr_divisor.join();
return 0;
}
【问题讨论】:
标签: c++ linux c++11 gdb pthreads