关键词:sched_yield()、nanosleep()等等。

sched_yield()主动放弃CPU执行权,nanosleep()是睡眠一段时间后再唤醒。

1. sched_yield()实现

sched_yield()会主动放弃当前CPU给其他进程使用;但是如果当前CPU上无其他进程等待执行,则直接返回继续执行当前进程。

调用sched_yield()之后当前进程会被移动到进程优先级等待队列尾部,让相同或者更高优先级进程运行。

sched_yield()确保当前进程在资源竞争严重时,给其他进程执行机会来提高性能。

SYSCALL_DEFINE0(sched_yield)
{
struct rq *rq = this_rq_lock(); schedstat_inc(rq->yld_count);
current->sched_class->yield_task(rq); __release(rq->lock);
spin_release(&rq->lock.dep_map, , _THIS_IP_);
do_raw_spin_unlock(&rq->lock);
sched_preempt_enable_no_resched(); schedule(); return ;
} asmlinkage __visible void __sched schedule(void)
{
struct task_struct *tsk = current; sched_submit_work(tsk);
do {
preempt_disable();
__schedule(false);
sched_preempt_enable_no_resched();
} while (need_resched());
} static void __sched notrace __schedule(bool preempt)
{
struct task_struct *prev, *next;
unsigned long *switch_count;
struct pin_cookie cookie;
struct rq *rq;
int cpu;
...
next = pick_next_task(rq, prev, cookie);---------------------选择优先级最高的进程作为下一个运行进程。
clear_tsk_need_resched(prev);
clear_preempt_need_resched();
rq->clock_skip_update = ; if (likely(prev != next)) {----------------------------------如果sched_yield()后,当前进程prev即为优先级最高的进程,即prev==next。那么则不会进行进程切换操作,直接返回。
rq->nr_switches++;
rq->curr = next;
++*switch_count; trace_sched_switch(preempt, prev, next);
rq = context_switch(rq, prev, next, cookie); /* unlocks the rq */
} else {
lockdep_unpin_lock(&rq->lock, cookie);
raw_spin_unlock_irq(&rq->lock);
} balance_callback(rq);
}

对于CFS调度器类,yield_task()对应yield_task_fair()。

static void yield_task_fair(struct rq *rq)
{
struct task_struct *curr = rq->curr;
struct cfs_rq *cfs_rq = task_cfs_rq(curr);
struct sched_entity *se = &curr->se; if (unlikely(rq->nr_running == ))--------------------如果当前运行队列上仅有一个运行进程,直接返回。
return; clear_buddies(cfs_rq, se); if (curr->policy != SCHED_BATCH) {
update_rq_clock(rq); update_curr(cfs_rq); rq_clock_skip_update(rq, true);
} set_skip_buddy(se);
}

下面是系统无其他进程运行时,可以看出进程独占了CPU很长时间。只是在有其他内核线程运行后,才放弃CPU执行权。

2. nanosleep()和sched_yield()对比

2.1 while(true)尽量独占CPU

#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <time.h> std::mutex g_mutex;
std::atomic<bool> ready(false); void count1m(int id)
{
while (true)
{
}
} int main()
{
std::thread threads; threads = std::thread(count1m, );
threads.join(); return ;
}

这种情况进程会尽可能独占整个CPU,但是在有竞争进程存在的时候,需要和其他进程均分CPU时间。所以出现下面每工作4ms,然后切换出去4ms时间的情况。

在没有其他进程运行的时候,可以独占CPU时间。

2.2 nanosleep()进程休眠一段时间

#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <time.h> std::mutex g_mutex;
std::atomic<bool> ready(false); void count1m(int id)
{
struct timespec delay;
delay.tv_sec = ;
delay.tv_nsec = ;
while (true)
{
nanosleep(&delay, NULL);
}
} int main()
{
std::thread threads; threads = std::thread(count1m, );
threads.join(); return ;
}

间隔休眠唤醒情况下,即使系统中存在其他进程在运行,当前进程唤醒后仍然可以抢到CPU资源,sched_switch表示放入队列,sched_wakeup表示得到CPU资源,中间可能存在一定延时。

在没有其他进程情况下,能更快得到调度。

2.3 sched_yield()主动放弃

#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <time.h> std::mutex g_mutex;
std::atomic<bool> ready(false); void count1m(int id)
{
while (true)
{
std::this_thread::yield();
}
} int main()
{
std::thread threads; threads = std::thread(count1m, );
threads.join(); return ;
}

这种情况和第一种区别在于,sched_yield()会主动放弃CPU执行权。第一种情况是根据CFS调度器类来分配时间;这里还结合了进程主动放弃调度的情况。

2.4 sched_yield()和nanosleep()混合使用

#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <time.h> std::mutex g_mutex;
std::atomic<bool> ready(false); void count1m(int id)
{
struct timespec delay;
delay.tv_sec = ;
delay.tv_nsec = ;
while (true)
{
std::this_thread::yield();
nanosleep(&delay, NULL);
}
} int main()
{
std::thread threads; threads = std::thread(count1m, );
threads.join(); return ;
}

这种情况下sched_yield()和nanosleep()叠加使用和单独使用nanosleep()效果类似,nanosleep()本省也是主动放弃CPU使用权。

所以综合来看while(1)中使用sched_yield()要比延时的响应更及时,但是也牺牲了CPU占用率。在没有其他进程运行的情况下,sched_yield()就会一个人独占CPU资源。

sched_yield()和nanosleep()对进程调度的影响的更多相关文章

  1. 《Linux/Unix系统编程手册》 时间子系统

    Linux下操作系统编程有两本经典APUE即<Advanced Programming in the UNIX Environment>和TLPI<The Linux Program ...

  2. 20135202闫佳歆--week 9 期中总结

    期中总结 前半学期的主要学习内容是学习mooc课程<Linux内核分析>以及课本<Linux内核设计与实现>. 所涉及知识点总结如下: 1. Linux内核启动的过程--以Me ...

  3. 一种基于PTP 协议的局域网高精度时钟同步方法(转)

    原文地址 http://www.dzsc.com/data/html/2011-1-17/88338.html 1 引言 在分布式系统中, 常常需要一个全局时间, 用来确定系统中各种事件发生的先后.协 ...

  4. Linux进程管理 (9)实时调度类分析,以及FIFO和RR对比实验

    关键词:rt_sched_class.SCHED_FIFO.SCHED_RR.sched_setscheduler().sched_setaffinity().RR_TIMESLICE. 本文主要关注 ...

  5. 8、Linux设备驱动的并发控制

    一.并发与竞争     并发是指多个 多个执行单元同时执行,而这对对共享的资源,比如硬件的资源.软件的全局变量.静态变量 的访问,很容易导致竞态, 1.1.中断屏蔽     在单核的  CPU 里,避 ...

  6. java web学习总结(二十六) -------------------JSP属性范围

    所谓的属性范围就是一个属性设置之后,可以经过多少个其他页面后仍然可以访问的保存范围. 一.JSP属性范围 JSP中提供了四种属性范围,四种属性范围分别指以下四种: 当前页:一个属性只能在一个页面中取得 ...

  7. javaweb学习总结(十八)——JSP属性范围

    所谓的属性范围就是一个属性设置之后,可以经过多少个其他页面后仍然可以访问的保存范围. 一.JSP属性范围 JSP中提供了四种属性范围,四种属性范围分别指以下四种: 当前页:一个属性只能在一个页面中取得 ...

  8. Linux进程调度

    原文地址: http://cchxm1978.blog.163.com/blog/static/35428253201092910491682/ 相当不错的文章,读了后收藏,多谢博主分享! ----- ...

  9. Linux系统编程——进程调度浅析

    概述 操作系统要实现多进程.进程调度不可缺少. 有人说,进程调度是操作系统中最为重要的一个部分.我认为这样的说法说得太绝对了一点,就像非常多人动辄就说"某某函数比某某函数效率高XX倍&quo ...

随机推荐

  1. ASP.NET Core on K8S深入学习(8)数据管理

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 在Docker中我们知道,要想实现数据的持久化(所谓Docker的数据持久化即 ...

  2. ES6 学习之 let

    关于闭包: <html> <body> <div> <div> <button >aaa</button> <button ...

  3. ASP.Net 设置 404错误跳转到指定页面

    分享 ASP.Net 网站设置 404错误跳转到指定页面的三种方法 方法一:Web.config 配置 1 首先双击打开项目中的“Web.config”文件  找到 system.web 节点,在 c ...

  4. 【坑】Maven [ERROR] 不再支持源选项 5。请使用 6 或更高版本

    在pom.xml文件中添加如下代码: 注意:jdk使用自己下载的版本,我的是13 <properties> <project.build.sourceEncoding>UTF- ...

  5. js自带的对数组中的操作

    这篇是我自己总结的,是我自己平常使用的不是很多的数组方法,而且都是js自带的,像大家经常使用的push.pop方法就没写里面.废话不多说,直接看代码 <!DOCTYPE html> < ...

  6. 字段明明存在,用Web API使用该字段进行查询报错?

    我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  7. Android插件基础之类加载器学习

    记录学习java 加载器学习所获心得,逐步记录了解java加载器的过程.为了知悉android 插件化的实现原理,从而需要从头了解android加载apk,以及基础的java类加载的加载过程情况,为方 ...

  8. 分布式全局唯一ID生成策略​

    一.背景 分布式系统中我们会对一些数据量大的业务进行分拆,如:用户表,订单表.因为数据量巨大一张表无法承接,就会对其进行分库分表. 但一旦涉及到分库分表,就会引申出分布式系统中唯一主键ID的生成问题. ...

  9. 配置 yum 源的两种方法

    配置 yum 源的两种方法 由于 redhat的yum在线更新是收费的,如果没有注册的话不能使用,如果要使用,需将redhat的yum卸载后,重启安装,再配置其他源,以下为详细过程:  1.删除red ...

  10. Vue+Vuex初体验

    首先: 安装vuex npm install vuex -S 需要有两个组件(HelloWord.vue 和 HelloDemo.vue)[组件自定义] 注册路由 注册store 测试 一.需要有两个 ...