创建进程
每个进程由进程ID号标识,进程被创建时系统就会为其分配一个唯一的进程ID.
创建进程的两种方式:
1.由操作系统创建
2.由父进程创建
*注意:
由操作系统创建的进程,它们之间是平等的,一般不存在资源继承关系.父进程创建的进程(子进程),它们和父进程存在隶属关系.子进程又可以创建进程,形成一个进程家族.子进程可以继承其父进程几乎所有的资源.
**创建一个子进程后,父进程和子进程争夺CPU,抢到CPU者执行,另外一个挂起等待.如果想要父进程等待子进程执行完毕以后再继续执行,可以在fork操作之后调用wait或waitpid
常见使用方法是子进程在被fork之和通过调用exec函数执行其他程序
fork函数
fork是创建一个新进程的唯一方法.在命令行下输入man 2 fork获得该函数的声明.
#include<stdio.h>
#include<unistd.h>
pid_t fork(void);
fork函数特别特殊,它有两个返回值,即调用一次,返回两次.
成功调用fork函数后,当前进程实际上已经分裂成两个进程,一个是原来的父进程,另一个是刚刚创建的子进程.
父子进程在调用fork函数的地方分开,两个返回值中,一个是父进程调用fork函数厚的返回值,该返回值是刚创建的子进程的ID,另一个是子进程中fork函数的返回值,该值为0,
fork函数返回两次的前提是进程创建成功,如果创建失败,则只返回-1.
区分父子进程:
父进程的返回值为新创建的子进程的进程ID,子进程返回值为0.
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main(void)
{
pid_t pid; //将pid定义为pid_t类型,等价于int pid;
pid = fork(); //调用fork函数创建自进程,pid用于记录返回值
switch(pid) {
case 0:printf("child process is running now,childpid is %d,parentpid is %d\n",pid,getppid() );
break;
case -1:printf("process creation failed\n");
break;
default:
printf("parent process is running now,childpid is %d,parentpid is %d\n",getpid(),pid);
break;
}
}
*可以知道:switch语句执行两次,一次在子进程执行,另一次在父进程执行
*一般来说,fork之后是父进程先执行还是子进程先执行是不确定的,取决于内核所使用的调度算法
*操作系统一般让所有进程都享有同等执行权,除非某些进程的优先级比其他的高
*fork函数在创建进程失败时,返回-1.失败原因通常是:父进程拥有的子进程个数超过了规定的限制.此时errno的值为EAGAIN,如果可供使用的内存不足也会导致进程创建失败.此时errno的值为ENOMEN.
*子进程和父进程的不同属性
1.子进程有它惟一的进程ID
2.fork的返回值不同
3.不同的父进程ID
4.子进程享有父进程打开的文件描述符.但父进程对文件描述符的改变不会影响子进程中的文件描述符
5.子进程不继承父进程设置的文件锁
6.子进程不继承父京城的警告
7.子进程未决信号集被清空
孤儿进程
*如果一个子进程的父进程先于子进程结束,子进程就成为一个孤儿进程,它由init进程收养,成为init进程的子进程
僵尸进程
一个子进程在其父进程还没有调用wait或waitpid的情况下退出,这个子进程就成为僵尸进程
僵尸进程会导致资源浪费,而孤儿进程则不会.
vfork函数
*vfork 和fork的详细对比
1.都是调用一次,返回两次
2.使用fork创建子进程时,子进程只是完全复制父进程的资源.这样得到的子进程独立于父进程,具有良好的并发性
3.使用vfork创建一个子进程时,操作系统并不将父进程的地址空间完全复制到子进程.而是共享父进程的地址空间,就是说子进程完全运行于父进程的地址空间上,子进程对该地址空间中任何数据的修改同样为父进程所见
4.使用fork创建时,哪个进程先运行取决于系统的调度算法
5.使用vfork创建时,保证子进程先执行,当它调用exec或exit后,父进程才有可能被调度运行.如果在调用exec或exit之前子进程要依赖父进程的某个行为,就会导致死锁.
创建守护进程
守护进程是指在后台运行的,没有控制终端与之相连的进程,独立于控制终端,通常周期性的执行某种任务.
>让进程在后台执行,方法:调用fork产生一个子进程,然后使得父进程退出.
>调用setsid创建一个新对话期
>禁止进程重新打开控制终端
>关闭不再需要的文件描述符
>将当前目录更改为根目录
>将文件创建时使用的屏蔽字设置为0
>处理SIGCHLD信号