一、进程
1.1 进程概念
程序:是文件,例如C语言程序,是静态的,没有生命周期,在磁盘上存放。
进程:是程序的一次执行过程是动态,具有生命周期,随着程序的开始而开始,结束而结束,在内存上存在 。进程是分配资源的最小单位,一旦进程被创建,系统就会给其分配0-3G内存空间,结束之后会回收。
1.2 进程的种类
交互进程: 有输入输出,由用户进行交互
批处理进程:在内核中的一个队列中,随着队列的运行而运行,例如gcc编译器
守护进程: 随着系统的开始而开始,结束而结束。类似于windows进程
1.3 特殊的进程
0:由系统创建,是1号进程和2号进程的父进程
1(init进程):在系统开始的时候初始化各种硬件设备,初始化完成之后,1号进程会回收各个孤儿进程的资源。
2:调度器进程
1.4 进程号PID
进程的唯一标识符,是一个非负整数
1.5 进程的基本状态
创建状态、就绪状态、运行状态、阻塞状态、结束状态
特殊状态的进程
孤儿进程:一个进程退出,但是由它创建的一个或者多个子进程还没有结束,此时这些子进程会成为孤儿进程
僵尸进程:子进程结束,但是父进程没有为其回收资源,所以它的PID还是存在,称为僵死进程。
1.6 进程相关命令
ps -ef
ps -ajx 查看当前系统进程详细信息(包括进程状态)
进程的状态:
R: 运行态
S: 可中断的等待态
X: 死亡态
Z: 僵尸态
T: 停止态
附加状态:
< : 高优先级的进程
N: 低优先级的进程
+ : 前台进程 //占用终端 可以使用&在执行进程的时候将进程以后台进程的形式运行
l : 小写的L 代表在当前这个进程中存在多线程
top :动态查看进程的状态
kill : 命令 例如:kill -13 pid,给进程号为pid的进程发送13号信号
killall a.out : 杀死所有名为a.out的进程(停止态不可杀死),在一个终端运行的进程,该终端会成为进程的父进程
二、进程的操作
2.1 进程的创建
函数原型:
pid_t fork(void);
功能:fork()通过复制调用进程来创建一个新进程。新进程称为子进程。调用进程称为父进程。
参数:无
返回值:成功:子进程返回0,父进程返回子进程的PID
失败:返回-1,子进程没有被创建,置位错误码
#include <stdio.h>
#include <unistd.h>
int main(){
pid_t pid;
int num = 10;
pid = fork(); //创建进程
if(-1 == pid){
perror("fork");return -1;
}else if(pid == 0){ //子进程
printf("this is child process\n");
num--;
printf("num = %d \n", num);
}else{ //父进程
sleep(1);
printf("this is parent process\n");
printf("num = %d \n", num);
}
//父子进程的先后执行顺序完全随机,时间片轮询
//写时拷贝,当子进程被创建出时,访问父进程的内存空间,但是一旦修改,就会开辟0-3G空间进行操作
return 0;
}
#include <stdio.h>
#include <unistd.h>
int main(){
for(int i = 0; i < 2; i++){
fork(); //父子进程都会执行
printf("1"); //如果不加\n会打印8个1,因为子进程是完全赋值父进程而来
//会将父进程的缓冲区内容也复制
//加上\n打印6个1
}
//fork()调用n次会创建2^n个进程
return 0;
}
2.2 获取进程号
函数原型:
pid_t getpid(void);//子进程
功能:获取调用进程的进程号
pid_t getppid(void);//父进程
功能:获取调用进程的父进程的进程号
#include <stdio.h>
#include <unistd.h>
int main(){
pid_t pid;
int num = 10;
pid = fork(); //创建进程
if(-1 == pid){
perror("fork");return -1;
}else if(pid == 0){ //子进程
printf("this is child process\n");
printf("子进程--pid = %d ppid = %d\n", getpid(), getppid());
}else{ //父进程
sleep(1);
printf("this is parent process\n");
printf("父进程--pid = %d ppid = %d\n", getpid(), getppid()); //父进程的父进程是终端进程
}
return 0;
}
2.3 进程退出
函数原型:
void exit(int status);
功能:正常退出一个进程
参数:
status: 退出时的状态,父进程会收到status & 0377的值
#define EXIT_SUCCESS 0 //没有任何差错退出当前进程
#define EXIT_FAILURE 1 //异常退出
函数原型:
void _exit(int status);
功能:立即终止一个进程的运行,该调用进程中所有打开的文件描述符都关闭,并且该进程的所有子进程都交由1号init进程继承,并且该进程 的父进程会收到一个SIGCHLD的信号
区别:exit()是库函数,当退出时会刷新缓冲区
_exit()是系统调用,退出时不会刷新缓冲区
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
pid_t pid;
int num = 10;
pid = fork(); //创建进程
if(-1 == pid){
perror("fork");
exit(1);
}else if(pid == 0){ //子进程
printf("this is child process\n");
printf("info from child process --1\n");
printf("info from child process --2");
exit(EXIT_SUCCESS); //一旦进程退出,后面的程序都不会运行
printf("info from child process --3\n");
}else{ //父进程
printf("this is parent process\n");
printf("info from parent process --1\n");
printf("info from parent process --2"); //不会打印,不会刷新缓冲区
_exit(0);
}
exit(0);
}
2.4 进程阻塞
函数原型:
pid_t wait(int *status);
功能:阻塞等待子进程状态修改(退出,被信号终止,被信号唤醒)
参数:
Status: 子进程退出时的状态,如果不想接收,填为NULL即可
返回值:成功返回子进程的PID ,失败-1
函数原型:
pid_t waitpid(pid_t pid, int *status, int options);
功能:默认状态下,waipid( )只等待被终止的子进程, 如果想要收到子进程其他状态修改的动作,可以通过修改第三个参数指定
参数:
pid :
-1:阻塞等待任何一个子进程退出
>0 : 阻塞等待进程号为pid的子进程退出
status: 子进程退出的状态,可以进一步使用宏进行判断子进程是如何终止
options: 是否附加函数其他功能
WNOHANG : 当调用该函数时,如果没有子进程退出,立即返回该函数
WUNTRACED : 也会接收子进程停止的状态
WCONTINUED : 也会接收子进程收到信号SIGCONT后恢复运行的状态