马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 moc 于 2018-11-5 20:39 编辑
1、fork系统调用
1. 进程原语 fork
头文件: <sys/types.h> 、 <unistd.h>
函数功能: 创建一个子进程
函数原型: pid_t fork(void);
参数: 无参数
返回值: 如果成功创建一个子进程,对于父进程来说返回子进程ID, 对于子进程来说返回值为0;如果为-1表示创建失败。
2. 复制一个进程映象fork
使用fork函数得到的子进程从父进程的继承了整个进程的地址空间,包括:进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设置、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等。
子进程与父进程的区别在于:
1. 父进程设置的锁,子进程不继承
2. 各自的进程ID和父进程ID不同
3. 子进程的未决告警被清除;
4. 子进程的未决信号集设置为空集。
3. 写时复制,读时共享copy on write, read on share
如果多个进程要读取它们自己的那部分资源的副本,那么复制是不必要的。
每个进程只要保存一个指向这个资源的指针就可以了。
如果一个进程要修改自己的那份资源的“副本”,那么就会复制那份资源。这就是写时复制的含义.
4. 注意点:
理解1:fork系统调用之后,父子进程将同时执行。
理解2:理解一次调用2次返回 => 两次返回,是在各自的进程空间中返回的。
理解3:理解,fork返回值大于零的是父进程,父进程:子进程 = 1:n。
理解4:理解分支在fork之后,父进程不是main函数的开始,而是紧接着向下执行,子进程从父进程的继承了整个进程的地址空间及数据。
示例:#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
int main(void )
{
pid_t pid;
signal(SIGCHLD, SIG_IGN);
printf("befor fork pid:%d \n", getpid());
int abc = 10;
pid = fork(); //errno
if (pid == -1)
{
//printf("pid < 0 err.\n");
perror("tile");
return -1;
}
if (pid > 0)
{
abc ++;
printf("parent: pid:%d \n", getpid());
printf("abc: %d \n", abc);
sleep(20);
}
else if (pid == 0)
{
abc ++;
printf("child: %d, parent: %d \n", getpid(), getppid());
printf("abc: %d \n", abc);
//sleep(10);
}
printf("fork after....\n");
return 0;
}
2、孤儿进程和僵尸进程
孤儿进程:
如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程(1号进程)。(注:任何一个进程都必须有父进程)
父亲进程先结束,子进程(孤儿进程)会托孤给1号进程。
僵尸进程:
如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵死进程。
避免僵尸进程
父进程忽略子进程的退出消息,交给操作系统管理。
#include <signal.h> ==> signal(SIGCHLD, SIG_IGN);
3、fork之后父子进程共享文件
如果父进程中打开了一个文件,那么子进程不需要再打开;子进程可以使用fork之前open返回的文件描述符。因为调用fork之后,只拷贝了PCB本身,拷贝的只是指针,没有拷贝指针所指向的内容,这种情况叫做浅拷贝。子进程的指针依旧指向struct file,所以父子进程对于文件描述符和文件偏移量是共享的。
4、fork和vfork
1)在fork还没实现copy on write之前。Unix设计者很关心fork之后立刻执行exec所造成的地址空间浪费,所以引入了vfork系统调用。
2)vfork有个限制,子进程必须立刻执行_exit或者exec函数。
即使fork实现了copy on write,效率也没有vfork高,但是我们不推荐使用vfork,因为几乎每一个vfork的实现,都或多或少存在一定的问题。
vfork现在已不推荐使用。
5、进程终止的5种方式
正常退出:
① 从main函数返回
② 调用exit
③ 调用_exit
异常退出:
④ 调用abort 产生SIGABOUT信号
⑤ 由信号终止 ctrl+c SIGINT等
1. exit与_exit区别
① _exit是一个系统调用,exit是一个c库函数;
② exit会执行清除I/O缓存;
③ exit会执行调用终止处理程序。int main(void)
{
printf("hello itcast");
//return 0;
//exit(0);
//fflush(stdout);
_exit(0); // 不会清除缓存,不会调用进程终止函数,所以没有打印结果
}
注册终止函数:
头文件: #include <stdio.h>
原型: int atexit(void (*func)(void))
作用: 在main函数return时或exit退出时,会自动调用。 |