进程的一生(四)

进程负载均衡

linux可能会运行在一个多核的状态下,linux就会在这些多核之间进行负载均衡,每个核的跑的相同的调度算法是我们之前提到的SCHED_FIFO和SCHED_RR和SCHED_NORMAL(CFS),linux就像一个分布式系统一样在不同核之间进行负载均衡,每个核都有可能把自己的task推到另一个核中,另一个核也有可能把task推给自己,对应pull和push,在多核的情况下,每个核都以劳动多为光荣,核空闲的时候会从别的核拉任务进来跑,我们使用time ./a.out执行程序后,见下图,real 对应实际使用的时间,user对应用户态使用时间,sys对应内核态使用时间,可以看出我们的程序中新建的两个线程被两个核瓜分跑了,所以user会是real的两倍时间
在这里插入图片描述
对于RT进程:N个优先级最高的RT自动分布到N个核
pull_rt_task()
push_rt_task()
对于普通进程,有下面三种均衡
周期性负载均衡:一个周期到来后,判断哪个核是闲的,哪个核是忙的,把忙核的部分task放到闲核上
IDLE时负载均衡:就是当一个核要跑0进程的时候,就会去看看旁边是否有其他核在工作,有的话拖它的工作来跑
fork和exec时负载均衡:当fork出一个新进程或exec转化到另外一个进程,就会发生负载均衡,分配给比较空闲的核来跑这写进程
看下面的一个例子

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
void *thread_fun(void *param)
{
  printf("thread pid:%d,tid:%lu\n",getpid(),pthread_self());
  while(1);
  return NULL;
}
int main(void)
{
   pthread_t tid1,tid2;
   int ret;
   printf("main pid:%d,tid:%lu\n",getpid(),pthread_self());
   pthread_create(&tid1,NULL,thread_fun,NULL);
   pthread_create(&tid1,NULL,thread_fun,NULL);
   pthread_join(tid1,NULL);
   pthread_join(tid1,NULL);
   return 0;
}

执行后按top命令看CPU占用率,可以看出我们是两个核在跑
在这里插入图片描述
下面的命令,01表示在第一个核跑,02表示在第二个核跑,03表示两个核一起跑,我们把它们变成一个核在跑,可以看出CPU占用率肯定一下子变为100%,两个线程挤到一个核去跑
在这里插入图片描述

中断的负载均衡

当我们把不同的中断号指向不同的核时就是中断的负载均衡,但是有些情况是无法中断负载均衡的,大家都知道在网卡驱动里面,CPU0收到一个中断以后,如果在中断里面再调用软件中断,CPU0又收到一个中断,那岂不是网卡上面的中断负载很重吗?这样就出现CPU0忙得要死,其他CPU在看热闹的情况,后来linux引入了RPS将包处理负载均衡到多个CPU,下面第一条命令就把软中断依次负载到其他核上
在这里插入图片描述

cgroup

在这里插入图片描述
cgroup讲的是进程的分群,当我们在服务器上面用1000个线程来编译我们的代码1(1000/1050的调用率 ),用50个线程来编译我们的另一段代码2,根据CFS,这对代码2(50/1050的调用率)很不公平,所以我们可以把代码1加到一个群1,代码2加到另一个群2,群1和群2的权重一致,看下面的例子,我们跑三个a.out
在这里插入图片描述
现在我们来进入/sys/fs/cgroup/cpu目录下,创建两个文件A,B,然后把线程10987和10981加入文件A的cgroup.procs,把线程10984加入文件B的cgroup.procs,查看CPU利用率,可以看出线程10987和10981加起来的CPU利用率和线程10984一致,因为cgroupA和B在调度时的权重一致
在这里插入图片描述

硬实时

所谓就是硬实时就是可预期性,就是要规定时间内完成响应,如果超出规定时间,就会出现灾难性的后果,Linux是软实时操作系统,响应超过规定的时间不会带来灾难性后果,顶多就是用户体验不好
在这里插入图片描述
linux跑起来后时间都花在4类区间上,分别是中断,软中断,不可调度进程(持有自旋锁的时候)和可调度进程,这4类中只有可调度进程可以调度抢占,在中断,软中断,不可调度进程中当你有任何一个优先级高的进程唤醒都不能抢占现在正在执行的进程,必须等这3类区间结束的一瞬间立即抢占,最后一个问题是Linux为什么不是硬实时,如下图所示
Normal task在t0时刻系统调用陷入了内核空间,然后它在t1时刻拿到spin_lock,一旦拿到spin_lock后核上的调度器就被关了,在t2时刻就进入中断,然后在t3时刻软中断就唤醒红色的RT task,理论此时RT task就应该抢占软中断,但是此时是软中断区间,我们提到软中断区间是不能够抢占的,所以此时RT task还是不能执行,到了t4时刻又进入一个中断,到了t5时刻中断就结束了,但是此时spin_lock还锁着呢,所以必须等到t6时刻spin_unlock后你的RT_task才能进来,所以这个时间段要多长RT_TASK才能执行时不确定的,是由程序员敲的代码工作量决定,既然时间不可预期,那么linux一定不会是硬实时操作系统,后来linux内核打进了PREEMPT_PT补丁,引入了互斥锁mutex,得不到互斥锁的进程就睡眠,对于spin_lock而言,在单核情况下如果spin_lock上锁后进程调度器就关了,在双核情况下另一个进程也去lock的话就会睡眠,还引入了中断线程化和软中断线程化,那么该线程就变成了第四类可调度线程,可以被其他线程抢占,就导致了很多位置都可以抢占了,但是中断服务程序依旧是不能抢的,如最后一张图看清linux内核抢占空间的发展过程
在这里插入图片描述
在这里插入图片描述

发布了83 篇原创文章 · 获赞 3 · 访问量 1240

猜你喜欢

转载自blog.csdn.net/qq_41936794/article/details/105391447