本文为宋宝华《Linux的进程、线程以及调度》学习笔记。

1 进程概念

1.1 进程与线程的定义

操作系统中的经典定义:

进程:资源分配单位。

线程:调度单位。

操作系统中用PCB(Process Control Block, 进程控制块)来描述进程。Linux中的PCB是task_struct结构体。

1.2 进程生命周期

1.2.1 进程状态

R, TASK_RUNNING:就绪态或者运行态,进程就绪可以运行,但是不一定正在占有CPU

S, TASK_INTERRUPTIBLE:浅度睡眠,等待资源,可以响应信号,一般是进程主动sleep进入的状态

D, TASK_UNINTERRUPTIBLE:深度睡眠,等待资源,不响应信号,典型场景是进程获取信号量阻塞

Z, TASK_ZOMBIE:僵尸态,进程已退出或者结束,但是父进程还不知道,没有回收时的状态

T, TASK_STOPED:停止,调试状态,收到SIGSTOP信号进程挂起

1.2.2 进程创建与消亡相关API

1) system()

通过调用shell启动一个新进程

2) exec()

以替换当前进程映像的方式启动一个新进程

3) fork()

以复制当前进程映像的方式启动一个新进程,子进程中fork()返回0,父进程fork()返回为子进程ID。

4) wait()

父进程挂起,等待子进程结束。

5) 孤儿进程与僵尸进程

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。孤儿进程不会浪费资源。

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。僵尸进程浪费系统资源(进程描述符task_struct存在,进程占用的资源被回收,不存在内存泄漏,实际上基本不浪费系统资源,参宋宝华的课程)。

避免僵尸进程:

僵尸进程产生原因:

1、子进程结束后向父进程发出SIGCHLD信号,父进程默认忽略了它;

2、父进程没有调用wait()或waitpid()函数来等待子进程的结束。

避免僵尸进程方法:

1、父进程调用wait()或者waitpid()等待子进程结束,这样处理父进程一般会阻塞在wait处而不能处理其他事情。

2、捕捉SIGCHLD信号,并在信号处理函数里面调用wait函数,这样处理可避免1中描述的问题。

3、fork两次,父进程创建儿子进程,儿子进程再创建一个孙子进程,然后儿子进程自杀,孙子进程成为孤儿进程被init进程收养。

1.3 进程间通信

1) 信号

信号这里指的是事件。比如按CTRL-C组合键会发送SIGINT信号,进程里可以捕捉到这个信号进行相应处理。

2) 管道PIPE

一切皆文件,管道的操作也是类似文件的操作。

popen()函数类似于fopen()函数,返回的是对象指针。

pipe()函数类似于open()函数,返回的是对象描述符。

管道是在亲属进程(同一父进程创建出的进程)之间进行数据传输的。

3) 命名管道FIFO

命名管道可用于在无亲属关系之前是进程间通信。

mkfifo()/mknod()将在文件系统中创建一个有路径和名称的文件。把这个管道文件当作普通文件用就行了,就可以实现进程间通信。

4) 信号量

信号量、消息队列、共享内存是System V IPC机制。

临界区:任何时刻只能有一个进程进行独占式访问的代码区。

信号量:大部分进程间通信只需要二进制信号号,因此这里只讨论二进制信号量。进入临界区前,执行P操作(若信号量大于1则减1并进入临界区,否则挂起本进程);退出临界区时,执行V操作(若有进程在等待挂起则唤醒之,否则信号量加1)。

互斥量:互斥信号量是二进制信号量的一个子集。

5) 消息队列

与命令管道类似,但不必考虑打开/关闭管道的复杂操作。消息队列独立于进程而存在。

6) 共享内存

需要通信的进程间共享一块内存进行数据交换。

2 进程线程的实现本质

Linux调度器实际是识别task_struct进行调度。

无论进程线程,底层都对应一个task_struct,进程和线程的区别是共享资源的多少,两个进程间完全不共享资源,两个线程间共享所有资源。

2.1 fork()

执行fork后,父进程的task_struck对拷给子进程,父子进程最初资源完全一样,但是两份不同拷贝,因此任何改动都造成二者的分裂。

父子进程对内存资源(mm)的管理使用了COW(Copy-On-Write, 写时拷贝)技术:

  1. 在fork之前,一片内存区对应一份物理地址和一份虚拟地址,内存区的权限的RW;
  2. 在fork之后,父子进程看到的内存区虚拟地址相同,物理地址也相同,父子进程使用的其实是同一片物理内存,未发生内存拷贝,操作系统会将此内存区权限改为RO;
  3. 父或子进程对内存区执行写操作将触发PageFault,操作系统此时会将内存区拷贝一份,父子进程看到的虚拟地址仍然一样,但是物理地址已经不则。各进程虚拟地址到物理地址的映射由MMU(Memory Management Unit, 内存管理单元)管理。

fork运行在有MMU的CPU上。

2.2 vfork()



对于无MMU的CPU,无法应用COW,无法支持fork。

无MMU的CPU使用vfork创建进程,父进程将一直阻塞直到子进程exit或exec。

vfork和fork的本质区别是,vfork中的父子进程共用同一片内存区。

2.3 pthread_create()



Linux线程本质上就是进程,只是线程间共享所有资源。如上图所示。

每个线程都有自己的task_struct,因为每个线程可被CPU调度。多线程间又共享同一进程资源。这两点刚好满足线程的定义。

Linux就是这样用进程实现了线程,所以线程又称为轻量级进程。

2.4 PID和TGID



POSIX要求,同一进程的多个线程获取进程ID是得到的是唯一ID值。

Linux同一进程的多线程,在内核视角实际上每个线程都有一个PID,但在用户空间需要getpid返回唯一值,Linux使用了一个小技巧,引入了TGID的概念,getpid()返回的的TGID值。

进程视角的top命令:

不带参数的top命令(默认情况),显示的是进程对单核CPU的利用率,例如,一个进程内有三个线程,主线程创建了线程1和线程2,线程1和线程2都调用一个while(1),则对双核CPU而言,线程1和线程2各用一个核,占用率都是100%,则top命令看到的进程CPU利用率是200%,进程ID是主线程的PID(也是TGID)。

线程视角的top命令:

top –H命令从线程视角显示CPU占用率,上例中,将会显示,线程1占用率100%,线程2占用率100%。

说线程的PID,是指用户空间的进程ID,值就是TGID;当特别指出,线程在内核空间的PID,则指线程在内核中task_struct里特有的PID。

3 进程调度

3.1 实时进程调度

SCHED_FIFO:不同优先级按照优先级高的先跑到睡眠,优先级低的再跑;同等优先级先进先出。

SCHED_RR:不同优先级按照优先级高的先跑到睡眠,优先级低的再跑;同等优先级轮转。

内核RT补丁:

/proc/sys/kernel/sched_rt_period_us

/proc/sys/kernel/sched_rt_runtime_us

在period的时间里RT最多只能跑runtime的时间

3.2 普通进程调度

SCHED_OTHER:

3.2.1 动态优先级(早期2.6)

进程有IO消耗性和CPU消耗型两种衡量参数。

优先级高的意味着:1) 得到更多的时间片,2) 醒时能抢占优先级低的。时间片轮转。

内核存储静态优先级,用户可通过nice来修改静态优先级。

进程的动态优先级则是根据静态优先级实时计算出来的,调度算法奖励IO消耗性(调高优先级增加实时性)、处罚CPU消耗型(调低优先级减小实时性)

3.2.2 CFS:完全公平调度(新内核)

红黑树,左边节点小于右边节点的值

运行到目前为止vruntime最小的进程

同时考虑了CPU/IO和nice

总是找vruntime最小的线程调度。

vruntime = pruntime/weight × 1024;

vruntime是虚拟运行时间,pruntime是物理运行时间,weight权重由nice值决定(nice越低权重越高),则运行时间少、nice值低的的线程vruntime小,将得到优先调度。这是一个随运行而动态变化的过程。

工具chrt和renice:

  1. 设置SCHED_FIFO50 RT优先级
  2. # chrt -f -a -p 50 10576
  3. 设置nice
  4. # renice -n -5 -g 9394
  5. # nice -n 5 ./a.out

4 多核负载均衡

5 参考资料

[1] 宋宝华,Linux进程、线程和调度

[2] https://blog.csdn.net/sdkdlwk/article/details/65938204

[3] https://blog.csdn.net/kklvsports/article/details/52268085

[4] https://blog.csdn.net/qq_20218109/article/details/52078076

[5] https://www.cnblogs.com/yuxingfirst/p/3165407.html

Linux的进程线程及调度的更多相关文章

  1. [转帖]Linux的进程线程及调度

    Linux的进程线程及调度 本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10393707.html 本文为宋宝华<Linux的进程 ...

  2. Linux查看进程线程个数

    1.根据进程号进行查询: # pstree -p 进程号 # top -Hp 进程号 2.根据进程名字进行查询: # pstree -p `ps -e | grep server | awk '{pr ...

  3. Linux下进程线程,Nignx与php-fpm的进程线程方式

    1.进程与线程区别 进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集.从内核的观点看,进程的目的就是担当分配系统资源(CPU时间.内存等)的基本单位. 线程是进程的一个执行流, ...

  4. Linux内核——进程管理与调度

    进程的管理与调度 进程管理 进程描写叙述符及任务结构 进程存放在叫做任务队列(tasklist)的双向循环链表中.链表中的每一项包括一个详细进程的全部信息,类型为task_struct,称为进程描写叙 ...

  5. Linux的进程/线程间通信方式总结

    Linux系统中的进程间通信方式主要以下几种: 同一主机上的进程通信方式 * UNIX进程间通信方式: 包括管道(PIPE), 有名管道(FIFO), 和信号(Signal) * System V进程 ...

  6. Linux的进程/线程通信方式总结(转)

    Linux系统中的进程通信方式主要以下几种: 同一主机上的进程通信方式 * UNIX进程间通信方式: 包括管道(PIPE), 有名管道(FIFO), 和信号(Signal) * System V进程通 ...

  7. [转载]了解Linux的进程与线程

    本文转自Tim Yang的博客http://timyang.net/linux/linux-process/ .对于理解Linux的进程与线程非常有帮助.支持原创.尊重原创,分享知识! 上周碰到部署在 ...

  8. linux常见进程与内核线程

    发现大量jdb2进程占用io资源.jdb2进程是一个文件系统的写journal的进程 kthreadd:这种内核线程只有一个,它的作用是管理调度其它的内核线程.它在内核初始化的时候被创建,会循环运行一 ...

  9. Linux下进程的创建过程分析(_do_fork do_fork详解)--Linux进程的管理与调度(八)

    Unix标准的复制进程的系统调用时fork(即分叉),但是Linux,BSD等操作系统并不止实现这一个,确切的说linux实现了三个,fork,vfork,clone(确切说vfork创造出来的是轻量 ...

随机推荐

  1. .net 简单任务调度平台安装简要说明

    .net 简单任务调度平台,用于.net dll,exe的任务的挂载,任务的隔离,调度执行,访问权限控制,监控,管理,日志,错误预警,性能分析等. 平台基于quartz.net进行任务调度功能开发,采 ...

  2. kbmmw中向服务器端传递对象的一种简单方式

    运行环境:delphi 10.2+kbmmw 5.6.20 在kbmmw 的老版本中,要向服务器传送一个本地的对象,一般都需要进行一些转换,例如通过序列化的方式. 在新版的kbmmw中这一切都变的很简 ...

  3. memmove、memcpy和memccpy简介

    memmove.memcpy和memccpy三个函数都是内存的拷贝,从一个缓冲区拷贝到另一个缓冲区.memmove(void *dest,void*src,int count)memcpy(void ...

  4. POJ1862 Stripies 贪心 B

    POJ 1862 Stripies https://vjudge.net/problem/POJ-1862 题目:     Our chemical biologists have invented ...

  5. ABP框架系列之十九:(Debugging-调试)

    While it's not generally needed, you may want to step into ABP's source code while you debugging you ...

  6. FZU.Software Engineering1816 ·The Second Assignment of the Team

    1.Team Leader Link:        柯奇豪:点我 2.NABCD Model: Need(需求)——客户需求是什么? *. 希望能够有一款集成日常办公所需功能的软件(如:想法搜集.投 ...

  7. 完整的SOPC开发流程体验

    课程目标:学习并掌握完整的SOPC开发流程. 开发环境:Quartus15.1 学习内容:1.使用QSYS工具建立能够运行流水灯项目的NIOS II处理器系统 2.在quartus ii中添加NIOS ...

  8. SQL Server使用证书最小粒度授权

    最近在项目中某个功能遇到了阻塞造成的Time out错误.所以需要在执行该功能的时候开启一个线程检测SQL Server中阻塞会话.但是程序本身使用的sql帐号本身不具备VIEW Sever Stat ...

  9. iOS安装包瘦身的那些事儿

    在我们提交安装包到App Store的时候,如果安装包过大,有可能会收到类似如下内容的一封邮件: 收到这封邮件的时候,意味着安装包在App Store上下载的时候,有的设备下载的安装包大小会超过100 ...

  10. iOS编码规范(简版)

    1. 总体指导原则 [规则1-1]首先是为人编写程序,其次才是计算机. 说明:这是软件开发的基本要点,软件的生命周期贯穿产品的开发.测试.生产.用户使用.版本升级和后期维护等长期过程,只有易读.易维护 ...