一、进程的查看(ps top)
ps指令
top指令
二,进程标识符pid的查看( getpid() getppid() )
进程标识符:进程标识符(PID)是一个进程的基本属性,其作用类似于每个人的身份证号码。根据进程标识符,用户可以精确地定位一个进程。一个进程标识符唯一对应一个进程,而多个进程标识符可以对应同一个程序。
0标识系统的调度进程,1表示系统的初始化进程。
函数原型:
pid_t getpid(void);//获取当前进程的pid
pid_t getppid(void);//获取当前进程的父进程的pid
返回值:
进程的标识符
用例:
pid_t pid;
pid=getpid();
printf("pid=%d\n",pid);
三、进程的创建(fork() vfork())
1、fork函数
函数原型:
pid_t fork(void);
返回值:
函数调用成功,函数返回两次,返回值为0,代表当前进程为进程,返回值为非负数,代表当前进程为父进程。调用失败,返回-1。
用例:
pid_t pid=fork();
if(pid>0){
printf("父进程\n");
}
else if(pid==0){
printf("子进程\n");
}
2、vfork函数
vfork函数需要与exit(),_exit(),_Exit,wait()等函数使用。第四节会讲数进程的退出。
函数原型:
pid_t vfork(void);
返回值:
函数调用成功,函数返回两次,返回值为0,代表当前进程为进程,返回值为非负数,代表当前进程为父进程。调用失败,返回-1。
用例:
int i=3;
pid_t pid=vfork();
if(pid>0){
wait(NULL);
printf("父进程\n");
}
else if(pid==0){
while(i--){
printf("子进程\n");
}
exit(0);
}
3、fork与vfork的异同
相同点:二者的用法都一样,返回值也相同。
区别:
1、在fork中,父进程与子进程公用存储空间,当子进程要对数据段的数据改变时在拷贝一份数据。而在vfork中子进程直接使用父进程的存储空间,不拷贝,此处需要要简单了解一下程序在内存中是怎样存储的。
命令行参数和环境变量 |
栈 |
..................... |
堆(malloc等开辟的空间) |
bss段(未被初始化的数据) |
数据段(已经初始化的数据) |
代码段(正文内容) |
2、vfork保证子进程先执行,子进程结束后,父进程才执行。fork中子进程和父进程的执行顺序是由系统的调度决定的,谁先执行轮到谁执行了都是系统调度进程决定的。
下面用代码来展示二者的区别。下面两段代码都在子进程中对变量a的值+1了,但在父进程中a的值却不一样,在fork中,父进程中a的值没有变,在子进程中+1了,变为了11,在vfork语句中,同样在子进程中对a的值+1了,但是父进程的值也变为了11,原因就是上述的区别1。在fork语句中,子进程对变量a的值进行改变时,会拷贝一份在自己的存储空间,此时在父进程和子进程中各有一块区域来存放变量a,是两个变量了。而在vfrok语句中,父子进程共用存储空间,所以子进程改变了a的值,父进程打印出来的a的值也跟着改变了,他们用的是一个a。
fork代码:
int a=10;
pid_t pid=fork();
if(pid>0){
printf("father a=%d\n",a);
}
else if(pid==0){
a++;
printf("son a=%d\n",a);
}
运行结果:
father a=10
son a=11
vfork代码:
int a=10;
pid_t pid=vfork();
if(pid>0){
wait(NULL);
printf("father");
}
else if(pid==0){
a++;
printf("son");
exit(3);
}
printf("\t a=%d\n",a);
运行结果:
son a=11
father a=11
四、父进程等待子进程的退出
在实际的应用过程过,父进程需要知道子进程的状态以及完成情况,所以需要等待子进程的状态。需要使用的函数为wait,waitpid和exit,_exit,_Exit。
僵尸进程:子进程的退出状态不被收集,就会变为僵尸进程。
函数原型:
pid_t wait(int *status)
void _exit(int status);
参数说明:
status是一个整型指针,子进程的退出状态就存放在它所指向的地址中。为NULL时表示不关心子进程的退出状态。
用例:
int a=10;
int *status;
pid_t pid=vfork();
if(pid>0){
wait(status);
printf("father status:%d\n",WEXITSTATUS(status));
}
else if(pid==0){
a++;
printf("son");
exit(3);
}
printf("\t a=%d\n",a);
以上述代码为例,wait会阻塞父进程的运行,wait后面的语句不会执行,直到子进程执行完,exit发送退出状态码,wait收集到这个状态码,父进程才会执行。WEXITSTATUS函数可以解析这个状态码。