不期待突如其来的好运,
只希望所有的努力终有回报!
目录
专业知识 | 操作系统与网络 | 4. Linux进程(process)
4.1 冯诺依曼体系结构
4.1.1 计算机的四个主要结构化部件
(1)处理器(propcessor)
- 控制计算机的操作,执行数据处理功能,通常指CPU(中央处理器);
- 通常使用两个内部存储器:存储器地址寄存器(确定下一次读写的存储器地址)和存储器缓冲寄存器(存放要写入存储器的数据或者从存储器中读取的数据);
(2)内存(main memory)
- 内存通常称为实存储器(real memory)或主存储器(primary memory),存储数据和程
序; - 特点:易失性。
(3)输入输出模块(I/O module)
- 在计算机和外部环境之间移动数据,外部环境由各种外部设备组成,包括辅助存储器设备
(如硬盘)、通信设备和终端;
(4)系统总线(system bus)
- 为处理器、内存和输入/输出模块间提供通信的设施。
4.2 操作系统概念与定位
4.2.1 概念
- 任何计算机系统都包含一个基本的程序集合,称为操作系统(OS),笼统的理解,操作系统包括:内核(进程管理,内存管理,文件管理,驱动管理)其他程序(例如函数库,shell程序等等)。
4.2.2 设计目的
- 1.与硬件交互,管理所有的软硬件资源;
- 2.为用户程序(应用程序)提供一个良好的执行环境。
4.2.3 定位
- 在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件。
4.2.4 系统调用和库函数
(1)定义
系统调用
- 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口叫做系统调用。
库函数
- 系统调用在使用上,功能比较基础,对用户的要求相对比较高,所以,有些开发者对部分系统调用进行适度封装,从而形成了库,有了库,就有利于更上层用于或者开发者进行二次开发。
(2)关系
- 库函数是对系统调用接口的一层封装,是上下级的调用关系。
4.2.5 如何理解管理
- 管理者并不需要直接与被管理者相互进行管理,而是通过对被管理者进行描述,并且将描述信息得当的,组织起来进行管理。
4.2.6 计算机管理硬件
- 先描述起来,用struct结构体;
- 再组织起来,用链表或其他高效的数据结构。
4.3 进程背景与定义
4.3.1 概念
- 1.从用户层面来说:进程就是运行起来的程序;
- 2.从操作系统的层面来理解:程序运行需要将代码加载到内存中,操作系统上运行了很多的程序,操作系统必须去管理这些程序的运行,先描述再组织进行管理,在操作系统的层面进程就是操作系统对一个运行的程序的描述。
4.3.2 描述进程-PCB
PCB
- 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。PCB(process control block),Linux操作系统下的PCB是: task_struct 结构体。
task_struct
- 在Linux中描述进程的结构体叫做task_struct。 task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。
task_struct的分类
- (1)标示符: 描述本进程的唯一标示符,用来区别其他进程;
- (2)状态: 任务状态,退出代码,退出信号等;
- (3)优先级: 相对于其他进程的优先级;
- (4)程序计数器: 程序中即将被执行的下一条指令的地址;
- (5)内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针;
- (6)上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器];
- (7)I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表;
- (8)记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等;
- (9)其他信息。
4.3.3 时间片
- CPU在每个程序上所运行的这段时间。
4.3.4 CPU的分时机制
- 轮询法去调度运行一个个程序,目的是为了让所有的程序都能同时推进。
4.4 描述进程
4.4.1 查看进程
- ps -aux | grep file
- ps -ef | grep file
4.4.2 通过系统调用
(1)获取进程标识符
- 进程id(PID);父进程id(PPID)
(2)创建进程fork
- man fork;fork有两个返回值;父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝技术)。
4.5 进程状态
4.5.1 五种状态模型
(1)R运行状态(running)
- 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
(2)S睡眠状态(sleeping)
- 意味着进程在等待时间完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
(3)D磁盘休眠状态(Disk sleep)
- 有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
(4) T停止状态(stopped)
- 可以通过发送SIGSTOP信号给进程来停止(T)进程。这个被暂停的进程可以通过发送
SIGCONT信号让进程继续运行。
(5) X死亡状态(dead)
- 这个状态只是一个返回状态,不会在任务列表里看到这个状态。
4.5.2 进程状态查看
(1)ps -aux | grep [文件名]
(2)ps -ef | grep [文件名]
4.5.3 僵尸进程Z(zombie)
(1)定义
- 在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用 waitpid()等待子进程结束, 又没有显式忽略该信号,处于僵死状态的进程,则子进程成为僵尸进程。
(2)产生原因
- 子进程先于父进程退出,因为要保留退出原因,因此操作系统不能直接释放所有资源,通知父进程获取退出原因,允许操作系统释放资源,但是父进程没有关注这个通知导致子进程退出后无法释放所有资源,处于僵死状态成为僵尸进程。
(3)如何避免
- 进程等待:
- 父进程调用wait和waitpid来等待子进程的结束,但是这将导致父进程的挂起,浪费资源;
(4)危害场景
- “擒贼先擒王”
4.5.4 孤儿进程
(1)定义
- 一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。
(2)产生原因
- 父进程先于子进程退出,子进程就会成为孤儿进程,运行在后台,父进程成为1号进程。
(3)如何避免
(4)危害场景
4.5.5 守护进程
(1)定义
- 守护进程是创建守护进程时有意把父进程结束,然后被1号进程init收养。守护进程会随着系统的启动默默的在后台运行,比如产生了很多的僵尸进程,那么守护进程的职责就是专门杀死父进程,这样就不会有僵尸进程了;类似看门狗程序(防止死机)就是守护进程。
(2)产生原因
(3)如何避免
(4)危害场景
4.6 进程调度
4.6.1 进程优先级
4.6.2 进程竞争性与独立性
(1)竞争性
- 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
(2)独立性
多进程运行,需要独享各种资源,多进程运行期间互不干扰。
4.6.3 并行与并发
(1)并行
- 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
(2)并发
- 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
4.7 环境变量
4.7.1 概念
- 一般是指在操作系统中用来指定操作系统运行环境的一些参数。
- 例如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
4.7.2 特性
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性;
4.7.3 相关命令
- env/set/echo
4.7.4 接口
- main的第三个参数/全局变量/envirin/getenv
4.7.5 常见环境变量
- PATH : 指定命令的搜索路径;
- HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录);
- SHELL : 当前Shell,它的值通常是/bin/bash。
4.8 程序地址空间
4.8.1 概念
- 实际上也就是虚拟地址空间即操作系统通过 mm_struct 这个结构体为进程描述一个空间,也称作内存描述符;通过页表的映射找到物理地址。
4.8.2 程序地址空间和页表的作用
- 1.提高内存利用率;
- 2.提供内存访问控制;
- 3.保证进程的独立性
4.8.3 为什么要使用虚拟地址空间
- 进程在通过访问地址进而获取变量数据,最终还是要去访问物理内存,因为物理数据是存储在物理内存中,在虚拟地址和物理地址之间通过页表进行地址映射,转换得到物理地址,进而访问到物理内存区域,通过映射之后,物理地址不一定连续,通过这种映射转换的方式实现数据的离散存储提高内存利用率。
4.8.4 操作系统中内存管理
分段式
- 通过地址中的段号去段表中找到段表项,通过段表中的物理地址加上地址中的段内偏移获取到物理地址。
分页式
- 通过地址中的页号去页表中找到页表项,通过页表项中的物理页号加上页内偏移获取到物理地址。
段页式
- 通过段号在段表中找到段表项,通过段表项中的段内页表地址找到段内页表,通过地址中的段内页号在段内也表中找到页表项,通过页表项中的物理页号与页内偏移组成物理地址。
4.9 代码
4.9.1 创建进程
/*===============================================================
* Copyright (C) . All rights reserved.")"
* 文件名称:create
* 创 建 者: yangjie
* 创建日期:
* 描 述: 进程创建
* pid_t fork(void);
* pid_t vfork(void);
* 通过复制调用进程, 创建一个新的子进程
* =============================================================*/
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello world-----pid:%d\n",getpid());
// pid_t fork(void);
// 创建一个子进程, 父进程返回子进程的pid, 子进程返回0
pid_t pid = fork();
if(pid < 0 )
{
printf("fork error!\n");
return -1;
}
else if(pid == 0)
{
printf("-----i am child-----:%d\n",getpid());
}
else
{
printf("-----i am parent----:%d\n",getpid());
}
printf("everything would be better!!!\n");
while(1)
{
printf("Believe yourself!\n");
sleep(1);
}
}
输出结果
[dev@localhost process]$ ./create
hello world-----pid:5629
-----i am parent----:5629
everything would be better!!!
Believe yourself!
-----i am child-----:5630
everything would be better!!!
Believe yourself!
Believe yourself!
Believe yourself!
Believe yourself!
Believe yourself!
Believe yourself!
Believe yourself!
Believe yourself!
Believe yourself!
^C
[dev@localhost process]$
4.9.2 环境变量
/*===============================================================
* Copyright (C) . All rights reserved.")"
* 文件名称:env
* 创 建 者: yangjie
* 创建日期:
* 描 述: 这个demo体现环境变量的全局特性
* int main(int argc, char* argv[], char* env[])
* =============================================================*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
// char* getenv(const char* name);
// 通过环境变量名获取内容
// char* ptr = getenv("~");
// printf("ptr: %s\n",ptr);
int i;
extern char** environ;
for(i = 0; environ[i]!= NULL; i++)
{
printf("env[%d]=[%s]\n",i,environ[i]);
}
return 0;
}
输出结果
[dev@localhost process]$ ./env
env[0]=[MANPATH=/opt/rh/devtoolset-4/root/usr/share/man:]
env[1]=[XDG_SESSION_ID=4]
env[2]=[HOSTNAME=localhost.localdomain]
env[3]=[SELINUX_ROLE_REQUESTED=]
env[4]=[TERM=xterm]
env[5]=[SHELL=/bin/bash]
env[6]=[HISTSIZE=4000]
env[7]=[SSH_CLIENT=192.168.136.1 5804 22]
env[8]=[PERL5LIB=/opt/rh/devtoolset-4/root//usr/lib64/perl5/vendor_perl:/opt/rh/devtoolset-4/root/usr/lib/perl5:/opt/rh/devtoolset-4/root//usr/share/perl5/vendor_perl]
env[9]=[SELINUX_USE_CURRENT_RANGE=]
env[10]=[OLDPWD=/home/dev/yangjie/LinuxOSandNET]
env[11]=[JAVACONFDIRS=/opt/rh/devtoolset-4/root/etc/java:/etc/java]
env[12]=[SSH_TTY=/dev/pts/2]
env[13]=[PCP_DIR=/opt/rh/devtoolset-4/root]
env[14]=[USER=dev]
env[15]=[LD_LIBRARY_PATH=/opt/rh/devtoolset-4/root/usr/lib64:/opt/rh/devtoolset-4/root/usr/lib::/home/dev/.VimForCpp/vim/bundle/YCM.so/el7.x86_64]
env[16]=[LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:]
env[17]=[XDG_CONFIG_DIRS=/opt/rh/devtoolset-4/root/etc/xdg:/etc/xdg]
env[18]=[MAIL=/var/spool/mail/dev]
env[19]=[PATH=/opt/rh/devtoolset-4/root/usr/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dev/.local/bin:/home/dev/bin]
env[20]=[PWD=/home/dev/yangjie/LinuxOSandNET/process]
env[21]=[LANG=zh_CN.UTF-8]
env[22]=[SELINUX_LEVEL_REQUESTED=]
env[23]=[HISTCONTROL=ignoredups]
env[24]=[SHLVL=1]
env[25]=[HOME=/home/dev]
env[26]=[PYTHONPATH=/opt/rh/devtoolset-4/root/usr/lib64/python2.7/site-packages:/opt/rh/devtoolset-4/root/usr/lib/python2.7/site-packages]
env[27]=[LOGNAME=dev]
env[28]=[XDG_DATA_DIRS=/opt/rh/devtoolset-4/root/usr/share:/usr/local/share:/usr/share]
env[29]=[SSH_CONNECTION=192.168.136.1 5804 192.168.136.128 22]
env[30]=[LESSOPEN=||/usr/bin/lesspipe.sh %s]
env[31]=[INFOPATH=/opt/rh/devtoolset-4/root/usr/share/info]
env[32]=[XDG_RUNTIME_DIR=/run/user/1000]
env[33]=[DISPLAY=localhost:12.0]
env[34]=[_=./env]
[dev@localhost process]$