进程相关概念
1.什么是程序,什么是进程,有什么区别?
程序是静态的概念,gcc xxx.c -o pro生成的pro文件叫做程序,进程是程序的一次运行活动,就是程序跑起来系统中多了一个进程,每个进程都一个非负整数表示唯一ID,叫pid
pid = 0 交换进程(swapper) 作用:进程调度
pid = 1 init进程 作用:系统初始化
一、进程创建
1.使用fork函数创建
pid_t fork(void);
fork函数调用成功,返回两次
返回值为0, 代表当前进程是子进程
返回值非负数,代表当前进程为父进程,且返回值是子进程的ID 号码
调用失败,返回-1
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid_t pid2;
pid_t returnpid;
pid = getpid();
printf("befer print:%d\n",pid);
returnpid = fork();
pid2 = getpid();
printf("after print:%d\n",pid2);
if(pid == pid2){
printf("this father print:%d returnpid=%d\n",getpid(),returnpid);
}else{
printf("this child print:%d returnpid=%d\n",getpid(),returnpid);
}
return 0;
}
运行结果
befer pint:8173
after print:8173
this father print:8173 returnpid=8174
after print:8174
this child print:8174 returnpid=0
fork之前的代码只有父进程再执行,fork之后的代码父进程子进程各自拥有一份,父进程子进程都会运行一次,至于谁先运行取决进程的调度。
2.使用vfork函数创建进程
vfork创建进程与fork的区别:
1.vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。
2.vfork 直接使用父进程存储空间,不拷贝,父进程的变量可以被子进程改变。
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
main()
{
int cnt = 0;
pid_t pid;
pid_t pid2;
pid = vfork();
if(pid > 0 ){
while(1){
printf("this father print:%d\n",getpid());
sleep(1);
printf("cnt=%d\n",cnt);
}
}else if(pid == 0){
while(1){
printf("this child print:%d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
exit(0);
}
}
}
return 0;
运行结果:等待子进程退出(使用正常退出)后,父进程才会执行,子进程使用父进程存储空间改变了父进程cnt的值
this child print:8680
this child print:8680
this child print:8680
this father print:8679
cnt=3
this father print:8679
cnt=3
this father print:8679
cnt=3
this father print:8679
二、进程创建目的
一个父进程希望复制自己,使父子进程同时执行不同的代码段。在网络服务器进程中,父进程等待客户端连接请求,当请求到达父进程调用fork,使得子进程处理请求,父进程继续等待下一个请求到来。前期是子进程代码全部copy父进程,后期是写操作copy。
三、进程退出
1.正常退出
1.Main函数调用return
2.进程调用exit(),标准c库
3.进程调用_exit()或者_Exit(),属于系统调用
补充:
1.进程最后一个线程返回
2.最后一个线程调用pthread_exit
2.异常退出
1.调用abort
2.当进程收到某些信号时,如ctrl+C
3.最后一个线程对取消(cancellation)请求做出响应
四、等待子进程退出
1.为什么要等待子进程退出
创建子进程执行时,想要知道子进程执行情况如何(活干完没,没干完是什么原因),此时父进程需要等待子进程退出并且收集子进程的退出状态。活干完了是正常退出根据状态码判断活干怎么样,活没干完就是异常退出根据退出状态码判断原因。子进程退出状态不被收集会变成僵死进程(僵尸进程)。
子进程调用exit函数,父进程调用wait函数收集退出状态, wait(&status),再用以下宏来解析结果
除了调用wait函数来收集退出状态,还可以使用waitpid,区别在于wait使使用者阻塞,waitpid有一个选项,可以使调用者不阻塞。相关函数原型如下
status参数:是一个整型数指针
非空:子进程退出状态放在它所指向的地址中。
空:不关心退出状态
通常使用pid>0
通常使用WNOHANG,挂起方式不阻塞
五、孤儿进程
父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程
Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程