Linux进程

目录

1.进程

2.进程控制

3.ps和kill命令

4.父子进程间的数据共享

5.exec函数族

6.孤儿进程和僵尸进程

7.进程回收

8.vfork创建进程

9.进程退出


1.进程

1. 进程的概念
程序:二进制文件,占用的磁盘空间
进程: 启动的程序
所有的数据都在内存中
需要占用更多的系统资源
cpu, 物理内存
2. 并行和并发
并发: 在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是 在同一个处理机上运行
并行: 当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。
其实决定并行的因素不是CPU的数量,而是CPU的核心数量,比如一个CPU多个核也可以并行
并行和并发的区别:
并发,指的是多个事情,在同一时间段内同时发生了。
并行,指的是多个事情,在同一时间点上同时发生了。
并发的多个任务之间是互相抢占资源的。
并行的多个任务之间是不互相抢占资源的。
只有在多 CPU 或者一个 CPU 多核的情况中,才会发生并行。否则,看似同时发生的事情,其实都是并发执行的。
3.PCB (进程控制块)
每个进程在内核中都有一个进程控制块( PCB )来维护进程相关的信息, linux 内核的进程控制块是 task_struct 结构体。
/user/src/linux-headers-3.16.0-30/include/linux/sched.h 头文件中可以查看 struct task_struct 结构体定义。内部成员有很多比如:
进程 id 。系统中每个进程有唯一的 id, C 语言中用 pit_t 类型表示,其实就是一个非负整数
进程的状态,有就绪,运行,挂起,停止等状态。
进程切换时需要保存和恢复一些 CPU 寄存器
描述虚拟地址空间的信息
描述控制终端的信息
当前工作目录( Cueernt Working Directory)
umask 掩码
文件描述符,包含很多指向 file 结构体的指针
和信号相关的信息
用户 id 和组 id,stat
会话( Session )和进程组
进程可以适用的资源上线( Resource Limit ,umilit -a
4. 进程状态
进程基本的状态有五种,分别为初始态,就绪态,运行态,挂起态和终止态。
其中初始态为进程准备阶段,常常与就绪态结合来看。

2.进程控制

1.fork函数

        一个进程,包括代码、数据和分配给进程的资源。
        fork ()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
       一个进程调用 fork ()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
包含的头文件:
#include <sys/types.h>
#include <unistd.h>
函数原型:
pid_t fork(void);
两个返回值:
=0 :当前进程为子进程
>0 :当前进程为父进程
‐1 ,出错
2.getpid/getppid 函数
getpid: 得到当前进程的 PID
getppid: 得到当前进程的父进程的 PID
父进程执行结束 子进程开始执行。

3.pskill命令

1.ps
查看进程信息
部分参数:
a : 显示现行终端机下的所有程序,包括其他用户的程序
u: 以用户为主的格式来显示程序状况
x: 显示所有程序,不以终端机来区分
2.kill
向指定的进程发送信号
kill 可将指定的信息送至程序。预设的信息为 SIGTERM(15) ,可将指定程序终止。若仍无法终止该程序,可使用
SIGKILL(9) 信息尝试强制删除程序。程序或工作的编号可利用 ps 指令或 job 指令查看。
参数:
-a :当处理当前进程时,不限制命令名和进程号的对应关系;
-l < 信息编号 > :若不加 < 信息编号 > 选项,则 -l 参数会列出全部的信息名称;
-p :指定 kill 命令只打印相关进程的进程号,而不发送任何信号;
-s < 信息名称或编号 > :指定要送出的信息;
-u :指定用户。
比如用kill函数终止程序:

4.父子进程间的数据共享

后续各自进行了不同的操作
各个进程的地址空间中的数据是完全独立的
对于同一个变量,读时共享
写的时候分别在物理地址上拷贝一份变量进行单独读写
父子进程之间可不可以通过全局变量通信?
不能,两个进程内存不能共享

5.exec函数族

让父子进程来执行不相干的操作
能够替换进程地址空间的代码.text段
执行另外的程序,不需要创建额外的的地址空间
当前程序中调用另外一个应用程序
指定执行目录下的程序 int execl(const char *path, const char *arg, ... /* (char *) NULL */);
我们发现此处值打印了一次i的值,这说明子进程调用exec函数后后面的文本就删除了。
/* path : 要执行程序的路径(最好是绝对路径) 变参arg : 要执行的程序需要的参数 第一位arg: 占位 后边的arg: 命令的参数 参数写完之后:null 一般执行自己写的程序 */
执行PATH环境变量能够搜索到的程序 int execlp(const char *file, const char *arg, ... /* (char *) NULL */);
返回值:
如果函数运行成功不返回
如果执行失败,打印错误信息,退出子进程

6.孤儿进程和僵尸进程

孤儿进程
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作
为了释放子进程的占用的系统资源:
进程结束之后,能够释放用户区空间
释放不了PCB,必须由父进程释放
此时由于父进程退出,子进程变为孤儿进程所以他所显示的父进程和前面不一致。
僵尸进程
一个比较特殊的状态,当进程退出父进程(使用wait()系统调用)没有读取到子进程退出的返回代码时就会产生僵尸进程。僵尸进程会在以终止状态保持在进程表中,并且会一直等待父进程读取退出状态代码。
此时子进程变为僵尸进程(z+),无法用kill命令关闭,只能通过kill父进程子进程才会消失。

7.进程回收

wait 阻塞函数
函数作用:
1. 阻塞并等待子进程退出
2. 回收子进程残留资源
3. 获取子进程结束状态(退出原因)
函数原型:pid_t wait(int *wstatus);
返回值:
‐1 : 回收失败,已经没有子进程了
>0 : 回收子进程对应的 pid
参数:
status 判断子进程如何退出状态
1.WIFEXITED(status): 为非 0 ,进程正常结束
WEXITSTATUS(status)
如上宏为真,使用此宏,获取进程退出状态的参数
2.WIFSIGNALED(status): 为非 0 ,进程异常退出
WTERMSIG(status):
如上宏为真,使用此宏,取得使进程种植的那个信号的编号
调用一次只能回收一个子进程
waitpid 函数
函数作用:同 wait 函数
函数原型:pid_t waitpid(pid_t pid, int *status, int options);
参数
1.pid: 指定回收某个子进程
pid == ‐1 回收所有子进程
while( (wpid=waitpid(‐1,status,0)) != ‐1)
pid > 0 回收某个 pid 相等的子进程
pid == 0 回收当前进程组的任一子进程
pid < 0 子进程的 PID 取反(加减号)
2.status: 子进程的退出状态,用法同 wait 函数
3.options: 设置为 WNOHANG, 函数非阻塞,设置为 0 ,函数阻塞
返回值:
>0 : 返回清理掉的子进程 ID
‐1 :回收失败,无子进程
如果为非阻塞
=0 :参数 3 WNOHANG, 且子进程正在运行
这里参数3设置为WNOHANG因为没有子进程回收,但是函数还是会执行,所以会一直打印wpid is 0. 为了防止一直打印wpid is 0在这里加上if语句使wpid等于0时不执行下面的命令。

8.vfork创建进程

vfork 也可以创建进程,与 fork 有什么区别呢?
区别一: vfork 可以直接使用父进程存储空间,不拷贝
区别二: vfork 可以保证子进程先运行,当子进程调用 exit 退出后,父进程才执行
可看出来 vfork 可以直接使用父进程存储空间,可以共享数据。

9.进程退出

1. 正常退出
1.main 函数调用 return
2. 进程调用 exit(), 标准 C
3. 进程调用 _exit() 或者 _Exit(), 属于系统调用
补充:
4. 进程最后一个线程返回
5. 最后一个线程调用 pthread_exit
2. 异常退出
1. 调用 abort 函数
2. 当进程收到某些信号时,比如 ctrl +C
3. 最后一个线程对取消( cancellation )请求做出相应
不管进程如何终止,最后都会执行内核中的同一段代码,这段代码和相应进程关闭所有打开描述符,释放它所使用的存储器等。
对上述任一一种终止情形,我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数 (exit, _exit和 _ Exit) ,实现这一点的方法是,将其退出状态 (exit status) 作为参数传送给函数,在异常终止情况下,内核 ( 不是进程本身) 产生一个指示其异常终止原因的终止状态 (termination status) 。在任意一种情况下,该终止进程的父进程都能用wait waitpid 函数取得终止状态。
#include <stdlib.h>
void exit(int status);
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void _Exit(int status);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值