赞
踩
程序: 二进制文件, 占用的磁盘空间
进程: 启动的程序, 所有数据都在内存, 不仅占用内存空间, 也需要占用更多的系统资源, 例如CPU, 物理内存
如图所示: 并发是两个队列交替使用一台咖啡机,并行是两个队列同时使用两台咖啡机
并发: 在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
并行: 是指“并排行走”或“同时实行或实施”。在操作系统中是指,一组程序按独立异步的速度执行,同一个时刻发生。要区别并发。并发是指:在同一个时间段内,两个或多个程序执行,有时间上的重叠(宏观上是同时,微观上仍是顺序执行)。
每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息, Linux内核的进程控制块是task_struct结构体
内部成员很多, 重点有:
int fork(void)
生成父进程和子进程, 有两个返回值, 分别由父进程和子进程返回. 父进程返回子进程的PID, 子进程返回0, 出错则返回-1.
fork之后的变量读时共享, 写时复制.
fork函数的返回值
>0, 父进程的返回值
=0, 子进程的返回值
子进程创建成功之后, 代码执行位置
从父进程执行的位置开始执行, 忽略之前的代码
父子进程的执行顺序
不一定, 看谁先抢到cpu
如何区分父子进程(通过返回值)
getpid()
获取当前进程的id
getppid
获取当前进程父进程的id
int main()
{
int i = 0;
int number = 5;
pid_t pid;
for(int i=0; i<number; ++i)
{
pid = fork();
if(pid == 0) // 子进程跳出循环
break;
}
//如何判断是第几个孩子
//通过循环因子判断
// 父进程
if(i == 3)
{
counter += 100;
printf("parent process, pid = %d, ppid = %d, %d\n", getpid(), getppid(), counter);
// sleep(1);
}
// 子进程
else if(i == 0)
{
// 1th
counter += 200;
printf("child process, pid = %d, ppid = %d, %d\n", getpid(), getppid(), counter);
}
else if(i == 1)
{
// 2th
counter += 300;
printf("child process, pid = %d, ppid = %d, %d\n", getpid(), getppid(), counter);
}
else if(i == 2)
{
// 3th
counter += 400;
printf("child process, pid = %d, ppid = %d, %d\n", getpid(), getppid(), counter);
}
return 0;
}
ps
ps aux | grep "xxx"
搜索进程
ps ajx | grep "xxx"
更加全面的搜索进程
kill
向指定的进程发送信号
查看信号 kill -l
杀死某个进程kill -9 PID
让父子进程执行不相干的操作
实现换核不换壳的功能
执行一个另外的程序不需要创建额外的地址空间
在当前程序调用另外一个的程序
首先想到exec之前需要fork
如果函数执行成功, 没有返回值, 如执行失败, 打印错误信息, 退出当前进程.
原型int execl(const char *path, const char *arg, ...)
;
path: 要执行的程序的路径
变参arg: 要执行的程序的需要的参数
第一个arg: 占位, 通常写执行程序的名字
后面的arg: 命令的参数
参数写完之后: NULL
一般执行自定义程序
原型int execp(const char *file, const char *arg, ...);
file: 执行的命令的名字
第一个arg: 占位
后边的arg: 命令的参数
参数写完后: NULL
执行系统自带的程序, 会在自动在目录/bin里搜索
例execlp("ps", "ps", "aux", NULL)
父进程已经被杀死, 子进程被init进程领养, init进程变成孤儿进程的父亲, ubuntu16.04变成被ui进程领养upstart
为了释放子进程占用的系统资源, 进程结束之后, 能够释放用户区空间, 释放不了pcb, 必须由父进程释放
孩子进程被杀死, 父进程还活着, 爹不去释放子进程的pcb, 孩子进程就变成了僵尸进程
是一个已经死掉的进程
wait 阻塞函数
pid_t wait(int* status);
返回值: -1: 失败, 已经没有子进程了. >0: 回收的子进程对应的pid
参数: status 判断子进程是如何死的, 正常退出,或被某个信号杀死了
调用一次只能回收一个子进程
waitpid –
pid_t fork(void);
○ 返回值:
成功:
□ 对于父进程来说返回子进程ID
□ 对于子进程来说返回值为0
失败
□ 如果为-1表示创建失败
获取当前进程ID
pid_t getpid(void);
○ 返回值:当前进程ID
获取当前进程的父进程ID
pid_t getppid(void);
○ 返回值:前进程的父进程ID
获取当前进程实际用户ID
uid_t getuid(void);
○ 返回值:当前进程实际用户ID
获取当前进程使用用户组ID
gid_t getgid(void);
○ 返回值:前进程使用用户组ID
int execl(const char *path, const char *arg, ...);
○ 函数描述:加载一个进程,通过路径 + 程序名来加载。
函数参数:
§ path:程序路径+程序名字
§ arg:可执行程序的相关参数,使用NULL结尾
返回值:
§ 成功:无返回
§ 失败:-1
int execlp(const char *file, const char *arg, ...);
函数描述:加载一个进程,借助PATH环境变量,
该函数需要配合PATH环境变量来使用,
当PATH中所有目录搜索后没有参数1则出错返回
函数参数:可执行程序的相关参数,使用NULL结尾
file:可执行程序的名字
arg:可执行程序的相关参数,使用NULL结尾
返回值:
成功:无返回
失败:-1
pid_t wait(int *status);
函数作用:
① 阻塞并等待子进程退出
② 回收子进程残留资源
③ 获取子进程结束状态(退出原因)。
返回值:
成功:清理掉的子进程ID;
失败:-1 (没有子进程)
参数:子进程的退出状态 – 传出参数
1. WIFEXITED(status):为非0 → 进程正常结束
WEXITSTATUS(status):
如上宏为真,使用此宏 → 获取进程退出状态 (exit/return)的参数)
2. WIFSIGNALED(status):为非0 → 进程异常终止
WTERMSIG(status):
如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。
pid_t waitpid(pid_t pid, int *status, in options);
函数作用:指定回收某个子进程
参数:
① pid:
pid == -1
回收所有子进程
- 循环回收
- while((wpid = waitpid(-1, $status, xx)) != -1)
???
pid > 0
某个子进程的PID
pid == 0
回收当前进程组的所有子进程
pid < -1
子进程的PID取反
② status: 子进程的退出状态,用法同wait函数
③ options:
设置为WNOHANG,函数非阻塞
设置为0,函数阻塞
返回值:
>0
:返回回收的子进程ID;
-1
:回收失败, 无子进程
如果为非阻塞: =0
子进程正在运行。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。