process
什么是进程
进程是被加载到内存中、正在运行的程序;多个进程可能对于同一个程序、一个正在运行的OS中会有多个进程
进程是程序的一次执行过程,是操作系统分配资源的基本单位
作业等同于进程
进程的布局:
每个进程都有一个不同的栈(函数调用,局部变量)
heap:动态分配内存
data section:存静态变量
text:程序代码
进程的状态
一个处理器上只有一个进程可以running,四核的机器可以有四个进程在running
操作系统会用PCB来表示进程,每个进程有且仅有一个PCB,PCB是进程的唯一表征
PCB在内存里
进程的创建
一个进程可以创建新的进程,创建新的进程是系统调用
传统的Unix系统用进程init作为所有用户进程的根进程,最近的Linux版本中,init被systemd替换了。systemd功能类似于init,但提供了更多服务
当子进程被创建时会需要一定的资源来完成任务。它可以从操作系统那里直接获取,也可以从父进程集继承(共享)一些资源
Unix系统中使用系统调用fork()来创建一个新进程,新进程时父进程的一份拷贝,它们只有pid和ppid不同以及子进程的当前内存使用记录为0,除此以外全部相同,fork()对父进程返回子进程的pid,对子进程返回0
fork()相当于创建副本
让子进程去干另外一件事就用excute系统调用
fork() :开一个进程,对于父进程的fork返回的是子进程的pid,子进程返回的fork是0
子进程用的还是父进程的代码,子进程对全局变量的修改不影响父进程
系统调用getpid()和getppid()可以分别获取进程的pid和ppid
进程的终止
系统调用exit()会使得进程终止,C语言main函数隐式返回exit()。除此之外进程也会由于一些信号、异常等终止
wait使得当前进程进入waiting状态,并在任一子进程终止或被信号停止、回复时进入ready状态,同时返回该事件的子进程的pid
当一个进程终止时,它进入terminated状态,它的资源被操作系统回收,但是操作系统仍然会保存一些信息等待父进程通过调用wait()来获取一些信息(pid)。当子进程已经终止,但父进程在忙并没有调用wait()时,我们称这样的子进程为僵尸进程,因为前述信息仍然在占据进程表中的一项,如果表满了就不能创建新的进程
当子进程没有结束但是父进程在没有调用wait()的情况下终止了,父进程就结束了,子进程就会成为孤儿进程,Linux的做法是让init进程收养它们,即init进程成为其父进程并定期调用wait进行释放
创建守护进程(在后台长期运行)的方法就是fork两次,kill child,让grandchild进行执行这一grandchild就会称为孤儿进程被init收养
进程间通信
举例:两个电脑之间的QQ通信
主要方式:共享内存和消息传递
进程间通信的方式:
- 信号量:操作系统的一种变量,是由操作系统来控制的不同进程可以访问的一个变量;可以通过sem_open()系统调用来建立和维护进程间的信号量;这样的信号量属于OS资源、它会在相关进程结束后由OS释放(传递的信息很少,只是一个变量而已)
-
共享内存:每一个进程都会有一个虚拟页表,每个虚拟页表会映射到物理的页上;有两个虚拟内存,映射到同一个物理地址指针上(冲突,可能会同时写同一个地址空间)
-
共享文件(很慢)
-
管道:半双工
-
消息队列:比较高级的手段,维护一堆链表,写东西就是往链表头写,操作系统去读
-
Socket,TCP/UDP
Linux内的操作
ps:显示静态进程
ps aux
a————列出系统当前所有进程
u————使用以用户格式为主的方式输出
x————该用户在终端下的所有进程
STAT——当前进程所处的状态(不同字符代表不同的状态:S表示可中断的休眠进程;s表示父进程;<表示优先级高的进程;R代表正在运行的进程;l代表多线性进程;N代表优先级低;Z代表僵尸进程;D代表不可中断的休眠进程;+代表的是前台进程)
top:显示动态进程
每三秒刷新一次
pgrep:查询进程PID
kill:杀死某个进程
killall:杀死含有关键字的所有进程
pkill:杀死指定用户/终端下的所有进程
参考链接:
https://www.yuque.com/xianyuxuan/coding/operating_systems
https://www.bilibili.com/video/BV1JW4y1j775/?spm_id_from=333.1007.top_right_bar_window_history.content.click