进程
程序---死的,存在磁盘上,不占用系统资源,编译好的二进制文件
进程---活得,运行的程序,占用系统资源
每个Linux进程都一定有一个唯一的数字标识符,称为进程ID(process ID)。进程ID总是一非负整数。
Linux启动过程有个init进程ID号是1,其它进程都是init派生出来的。 Linux启动过程有个init进程ID号是1,其它进程都是init派生出来的。
Linux下的进程结构
Linux系统是一个多进程的系统,进程之间具有并行性、互不干扰的特点。
Linux中进程包含3个段:代码段、数据段、堆栈段
数据段:存放全局变量、常数以及动态数据分配的空间(malloc函数取得的空间)
代码段:存放程序代码
堆栈段:存放子程序的返回地址、子程序的参数以及程序的局部变量
内存管理单元图
虚拟内存和物理内存映射
PCB进程控制块
/usr/src/linux-headers-3.16.0-30/include/linux/sched.h
文件中查看 struct task_struct结构体定义
内部成员:
进程id,pid_t
进程状态:就绪,运行,挂起,停止
进程切换时需要保存和恢复的一些cpu寄存器
描述虚拟地址空间的信息
描述控制终端的信息
当前工作目录
umask掩码
文件描述符表
和信号相关的信息
用户id和组id
进程控制
fork函数
pid_t fork(void)
创建子进程。父进程各自返回,父进程返回子进程pid。子进程返回0
getpid();
getppid()
循环创建5个进程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
int i;
for(i=0;i<5;i++){
if(fork()==0)
break;
}
if(i==5){
sleep(5);
printf("I'm parent
");
}
else{
sleep(i);
printf("I'm %d th
",i);
}
return 0;
}
进程共享
父子进程之间在fork后,有哪些相同,有哪些不同?
刚fork之后
父子相同处:1.全局变量,2..data、3..text、4.堆、5.栈、6.环境变量、7.用户ID、8.宿主目录、9.进程工作目录、10.信号处理方式
父子不同处:1.进程ID 2.fork返回值 3.父进程ID 4.进程运行时间 5.闹钟 6.未决信号集
父子进程共享:
读时共享,写时复制---------全局变量
1.文件描述符
2.nmap映射区
参考书:
《操作系统原理》 谢青松
《计算机硬件及组成原理》 Arnoid S.Berger
exec函数族
重点掌握:
int execl(const char *path,const char * arg,...);
int execlp(const char *file, const har *arg,...);
加载一个进程,借助 PATH 环境变量
int execlp(const char *file, const char *arg, ...);
成功:无返回;
失败:-1
参数 1:要加载的程序的名字。该函数需要配合 PATH 环境变量来使用,当 PATH 中 所有目录搜索后没有参数 1 则出错返回。 该函数通常用来调用系统程序。如:ls、date、cp、cat 等命令。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char*argv[]){
pid_t pid=fork(); //创建子进程
if(pid==-1){
perror("fork error");
exit(1);
}
else if(pid==0){ //子进程
// execlp("ls","-l","-d","-h",NULL); 错误写法
// execlp("ls","ls","-l","-h",NULL);
//execlp("date","date",NULL);
// execlp("./test","./test",NULL);
execl("./test","./test",NULL);
perror("exec error");
exit(1);
}
else if(pid>0){ //父进程
sleep(1);
printf("I'm parent:%d
",getpid());
}
return 0;
}
回收子进程
孤儿进程(父进程先挂,子进程变成孤儿):
父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程为init进程
称为init进程领养孤儿进程
僵尸进程(子进程挂了,父进程一直不回收,子进程变成僵尸进程)
僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的PCB资源,此时子进程将成为一个僵尸进程
特别注意,僵尸进程是不能使用kill命令清除掉的。因为kill命令是用来终止进程的,而僵尸进程已经终止。用什么办法可以清除僵尸进程?--------------杀死父进程
wait函数
父进程调用 wait 函数可以回收子进程终止信息。该函数有三个功能:
- 阻塞等待子进程退出
- 回收子进程残留资源
- 获取子进程结束状态(退出原因)。
pid_t wait(int *status);
成功:清理掉的子进程 ID;
失败:-1 (没有子进程)
可使用 wait 函数传出参数 status 来保存进程的退出状态。借助宏函数来进一步判断进 程终止的具体原因。宏函数可分为如下三组:
1.WIFEXITED(status) 为非 0 → 进程正常结束 WEXITSTATUS(status)
如上宏为真,使用此宏 → 获取进程退出状态 (exit 的参数)
-
WIFSIGNALED(status) 为非 0 → 进程异常终止 WTERMSIG(status)
如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。 -
WIFSTOPPED(status) 为非 0 → 进程处于暂停状态 WSTOPSIG(status)
如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。 WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行
waitpid函数 指定某一个进程进行回收
pid_t waitpid(pid_t pid,int *status,int options)
参数:
pid:指定回收的子进程id、
>0:待回收的子进程pid
-1:任意子进程
0:同组的子进程
status:(传出)回收进程的状态
options:WNOHANG 指定回收方式为:非阻塞
返回值:
>0:表示成功回收的子进程pid
0:函数调用时,参3指定了WNOHANG,并且,没有子进程结束。
-1:失败errno
总结:
wait,waitpid 一次调用,回收一个子进程
想回收多个,循环
waitpid(-1,&status,0)==wait(&status);