一、Linux下程序如何转化成进程?
- 内核将程序读入内存,为程序分配内存空间
- 内核为该进程分配进程标识符pid和其他所需资源
- 内核为该进程保存PID及相应的状态信息,把进程放到运行队列中等待执行.程序转化为进程后就可以被操作系统的调度程序调度执行了
1. fork() 创建一个新进程 调用格式:int pid=fork();
fork() 返回值意义如下:
0 :在子进程中,pid变量保存的fork()返回值为0,表示当前进程是子进程;
>0 : 在父进程中,pid变量保存的fork()返回值为子进程的id值(进程唯一标识符);
-1 : 创建失败(内存不够或进程太多)
如果fork()调用成功,它向父进程返回子进程的pid,并向子进程返回0,即fork()被调用了一次,但被返回了两次。
总结:父进程返回子进程pid,子进程返回 0 ,子进程和父进程独立运行。
2. getpid() 取得目前进程的识别码(进程ID)
getppid() 取得目前进程的父进程识别码
注意:包含头文件 #include<unistd.h>
二、进程创建实例
1、
#include<stdio.h>
#include<unistd.h> //这个头文件不要忘带了
int main(){
int p=fork();
while(p==-1); //进程创建失败
if(p==0){printf("child");} //子进程中
else{printf("parent");} //父进程中
return 0;
}
2、
3、
父进程id不一样是因为整个程序的运行时间太短,当子进程运行到getppid()时候父进程就已经结束并导致一些意外的结果(比如输出的id不同),我们需要加个sleep函数测试一下。
这样我们就能证明父进程在子进程结束后结束。
4、
#include<stdio.h>
#include<unistd.h>
int main(){
if(fork()||fork()){
printf("A\n");
}else{
printf("B\n");
}
return 0;
}
理解:|| 是符号或,1或0=1,0或=0,1或1=1
执行if里的fork(),原进程fork()一个子进程(进程1),原进程和进程1同时执行,原进程返回值为!0所以打印A,进程1的fork()返回值为0,所以判断if语句的第二个fork(),于是进程1fork()了一个进程2(进程1的子进程),返回值为!0,打印A,然后进程2的返回值为0,打印B。结果为AAB,但是顺序未知,因为子进程父进程在fork完成后是互不干扰的,不一定谁先结束。(异步性?)理论上父进程快于子进程。
5、
#include<stdio.h>
#include<unistd.h>
int main(){
for(int i=0;i<2;i++){
if(fork()){
printf("A");
}else{
printf("B");
}
}
return 0;
}
(加上pid和ppid后好理解点)
理解:i=0时,执行if语句,原进程fork()个进程1,原进程返回值为!0,所以打印A,进程1返回值为0,打印B。i=1时,原进程fork()个新进程(进程2),此时原进程打印A,进程2打印B,与此同时进程1fork()一个子进程(进程3),进程1打印A,进程3打印B。从而得到 3个A,3个B的结果。(最后创建了三个子进程)
三、execl()函数
功能:把一个新程序装入内存,来改变调用进程的执行代码,从而形成新的进程。
execl("路径",“可执行文件名”,NULL);
如果execl调用成功,调用进程将被覆盖,然后从新程序的入口开始执行,这样就产生了一个新进程。新进程的进程标识符id与调用进程相同,execl()没有建立一个与调用进程并发的子进程,而是用新进程取代了原来的进程。
在子进程中,调用execl函数
(vim a.c / gcc -o 1 a.c)
运行结果就一直产生新进程,循环