订阅
纠错
加入自媒体

Linux :多处理器遇到实时进程和普通进程的程序设计

2021-06-16 13:58
道哥分享
关注

问题很明显:为什么 4 个线程为什么被同时执行了?

1 号和 2 号这两个线程应该被优先执行啊,因为它俩是实时任务!

怎么结果是这个样子?彻底凌乱了,一点都不符合预期!

想不出个所以然,只能求助网络!但是没有找到有价值的线索。

其中有一个信息涉及到 Linux 系统的调度策略,这里记录一下。

Linux 系统中,为了不让实时任务彻底占据 CPU 资源,会让普通任务有很小的一段时间缝隙来执行。

在目录 /proc/sys/kernel 下面,有 2 个文件,用来限制实时任务占用 CPU 的时间:

sched_rt_runtime_us: 默认值 950000sched_rt_period_us: 默认值 1000000

意思是:在 1000000 微秒(1秒)的周期内,实时任务占用 950000 微秒(0.95秒),剩下的 0.05 秒留给普通任务。

如果没有这个限制的话,假如某个 SCHED_FIFO 任务的优先级特别高,恰巧出了 bug:一直占据 CPU 资源不放弃,那么我们压根就没有机会来 kill 掉这个实时任务,因为此时系统无法调度其他的任何进程来执行。

而有了这个限制呢,我们就可以利用这 0.05 秒的执行时间,来 kill 掉有 bug 的那个实时任务。

回到正题:资料上说,如果实时任务没有被优先调度,可以把这个时间限制删掉就可以了。方法是:

sysctl -w kernel.sched_rt_runtime_us=-1

我照做之后,依旧无效!

换一台虚拟机,继续测试

难道是电脑环境的问题吗?于是,把测试代码放到另一台笔记本里的虚拟机 Ubuntu14.04 里测试。

编译的时候,有一个小问题,提示错误:

error: ‘for’ loop initial declarations are only allowed in C99 mode

只要把编译指令中添加 C99 标准就可以了:

gcc -o test test.c -lpthread -std=c99

执行程序,打印信息如下:

====> thread_index = 2
====> thread_index = 1
thread_index 1: SCHED_FIFO
thread_index 1: priority = 51
thread_index 2: SCHED_FIFO
thread_index 2: priority = 52
thread_index 1: num = 0
thread_index 2: num = 0
thread_index 2: num = 1
thread_index 1: num = 1
thread_index 2: num = 2
thread_index 1: num = 2
thread_index 2: num = 3
thread_index 1: num = 3
thread_index 2: num = 4
thread_index 1: num = 4
thread_index 2: num = 5
thread_index 1: num = 5
thread_index 2: num = 6
thread_index 1: num = 6
thread_index 2: num = 7
thread_index 1: num = 7
thread_index 2: num = 8
thread_index 1: num = 8
thread_index 2: num = 9
thread_index 2: exit
====> thread_index = 4
thread_index 4: SCHED_OTHER
thread_index 4: priority = 0
thread_index 1: num = 9
thread_index 1: exit
====> thread_index = 3
thread_index 3: SCHED_OTHER
thread_index 3: priority = 0
thread_index 3: num = 0
thread_index 4: num = 0
thread_index 3: num = 1
thread_index 4: num = 1
thread_index 3: num = 2
thread_index 4: num = 2
thread_index 3: num = 3
thread_index 4: num = 3
thread_index 3: num = 4
thread_index 4: num = 4
thread_index 3: num = 5
thread_index 4: num = 5
thread_index 3: num = 6
thread_index 4: num = 6
thread_index 3: num = 7
thread_index 4: num = 7
thread_index 3: num = 8
thread_index 4: num = 8
thread_index 3: num = 9
thread_index 3: exit
thread_index 4: num = 9
thread_index 4: exit

1 号和 2 号线程同时执行,完毕之后,再 3 号和 4 号线程同时执行。

但是这同样也不符合预期:2 号线程的优先级比 1 号线程高,应该优先执行才对!

不知道应该怎么查这个问题了,想不出思路,只好请教 Linux 内核的大神,建议检查一下内核版本。

这时,我才想起来在 Ubuntu16.04 这台虚拟机上因为某种原因,降过内核版本。

往这个方向去排查了一下,最后确认也不是内核版本的差异导致的问题。

比较结果,寻找差异

只好再回过头来看一下这两次次打印信息的差异:

工作电脑里的 Ubuntu16.04 中:4 个线程同时调度执行,调度策略和优先级都没有起作用;

笔记本里的 Ubuntu14.04 中:1 号和 2 号实时任务被优先执行了,说明调度策略起作用了,但是优先级没有起作用;

突然, CPU 的亲和性从脑袋里蹦了出来!

紧接着立马感觉到问题出在哪里了:这TMD大概率就是多核引起的问题!

于是我把这 4 个线程都绑定到 CPU0 上去,也就是设置 CPU 亲和性。

在线程入口函数  thread_routine 的开头,增加下面的代码:

cpu_set_t mask;
int cpus = sysconf(_SC_NPROCESSORS_CONF);
CPU_ZERO(&mask);
CPU_SET(0, &mask);
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)

   printf("set thread affinity failed! ");

然后继续在 Ubuntu16.04 虚拟机中验证,打印信息很完美,完全符合预期:

====> thread_index = 1
====> thread_index = 2
thread_index 2: SCHED_FIFO
thread_index 2: priority = 52
thread_index 2: num = 0
。。。
thread_index 2: num = 9
thread_index 2: exit
thread_index 1: SCHED_FIFO
thread_index 1: priority = 51
thread_index 1: num = 0
。。。
thread_index 1: num = 9
thread_index 1: exit
====> thread_index = 3
thread_index 3: SCHED_OTHER
thread_index 3: priority = 0
====> thread_index = 4
thread_index 4: SCHED_OTHER
thread_index 4: priority = 0
thread_index 3: num = 0
thread_index 4: num = 0
。。。
thread_index 4: num = 8
thread_index 3: num = 8
thread_index 4: num = 9
thread_index 4: exit
thread_index 3: num = 9
thread_index 3: exit

至此,问题真相大白:就是多核处理器导致的问题!

而且这两台测试的虚拟机,安装的时候分配的 CPU 核心是不同的,所以才导致打印结果的不同。

真相大白

最后,再确认一下这 2 个虚拟机中的 CPU 信息:

Ubuntu 16.04 中 cpuinfo 信息:

$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model  : 158
model name : Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
stepping : 10
cpu MHz  : 2807.996
cache size : 9216 KB
physical id : 0
siblings : 4
core id  : 0
cpu cores : 4
。。。其他信息
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model  : 158
model name : Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
stepping : 10
cpu MHz  : 2807.996
cache size : 9216 KB
physical id : 0
siblings : 4
core id  : 1
cpu cores : 4
。。。其他信息
processor : 2
vendor_id : GenuineIntel
cpu family : 6
model  : 158
model name : Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
stepping : 10
cpu MHz  : 2807.996
cache size : 9216 KB
physical id : 0
siblings : 4
core id  : 2
cpu cores : 4
。。。其他信息
processor : 3
vendor_id : GenuineIntel
cpu family : 6
model  : 158
model name : Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
stepping : 10
cpu MHz  : 2807.996
cache size : 9216 KB
physical id : 0
siblings : 4
core id  : 3
cpu cores : 4
。。。

其他信息

在这台虚拟机中,正好有 4 个核心,而我的测试代码正好也创建了 4 个线程,于是每个核心被分配一个线程,一个都不闲着,同时执行。

因此打印信息中显示 4 个线程是并行执行的。

这个时候,什么调度策略、什么优先级,都不起作用了!(准确的说:调度策略和优先级,在线程所在的那个 CPU 中是起作用的)

如果我在测试代码中,一开始就创建 10 个线程,很可能会更快发现问题!

再来看看笔记本电脑里虚拟机 Ubuntu14.04 的 CPU 信息:

$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 142
model name : Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
stepping : 9
microcode : 0x9a
cpu MHz : 2304.000
cache size : 4096 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
。。。其他信息
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 142
model name : Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
stepping : 9
microcode : 0x9a
cpu MHz : 2304.000
cache size : 4096 KB
physical id : 0
siblings : 2
core id : 1
cpu cores : 2
。。。其他信息

在这台虚拟机中,有 2 个核心,于是 2 个实时任务 1 号和 2 号被优先执行(因为是 2 个核心同时执行,所以这 2 个任务的优先级也就没什么意义了),结束之后,再执行 3 号和 4 号线程。

再思考一下

这一圈测试下来,真的想用键盘敲自己的脑袋,怎么就没有早点考虑到多核的因素呢?!

深层的原因:

之前的很多项目,都是 ARM、mips、STM32等单核情况,思维定式让我没有早点意识到多核这个屏体因素;

做过的一些 x86 平台项目,并没有涉及到实时任务这样的要求。一般都是使用系统默认的调度策略,这也是 Linux x86 作为通用电脑,在调度策略上所关注的重要指标:让每一个任务都公平的使用 CPU 资源。

随着 x86 平台在工控领域的逐渐应用,实时性问题就显得更突出、更重要了。

所以才有了 Windows 系统中的 intime,Linux 系统中的 preempt、xenomai 等实时补丁。

<上一页  1  2  3  
声明: 本文由入驻维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。

发表评论

0条评论,0人参与

请输入评论内容...

请输入评论/评论长度6~500个字

您提交的评论过于频繁,请输入验证码继续

暂无评论

暂无评论

    人工智能 猎头职位 更多
    扫码关注公众号
    OFweek人工智能网
    获取更多精彩内容
    文章纠错
    x
    *文字标题:
    *纠错内容:
    联系邮箱:
    *验 证 码:

    粤公网安备 44030502002758号