《UNIX环境高级编程》学习笔记——进程控制(一)
来源:互联网 发布:09外设淘宝店地址 编辑:程序博客网 时间:2024/05/01 10:58
fork函数
一个现存的进程可以通过fork函数创建一个新的进程:
#include <unistd.h>pid_t fork(void); Returns:0 in child,process ID of child in parent, -1 on errorfork函数创建的新进程叫子进程。这个函数被调用一次,但返回两次。在子进程中该函数返回的值为0,而在父进程中该函数返回的是子进程的进程ID。
还有一个很重要的东西是,在fork()的调用处,整个父进程空间会原模原样地复制到子进程中,包括数据空间,堆,程序调用栈,环境变量,缓冲区,等等(不过父子进程共享正文段)。
由于在fork之后经常跟随着exec,所以现在的很多实现并不执行一个父进程数据段、栈和堆的完全复制。作为替代,使用了写时复制(Copy-On-Write, COW)技术。这些区域由父、子进程共享,而且内核将它们的访问权限改变为只读。如果父、子进程中的任一个试图修改这些区域,则内核只为修改区域的那块内存制作一个副本,通常是虚拟存储器系统中的一“页”。
为了更好的理解fork函数,这里给出一个有关fork函数的面试题:
请问下面的程序一共输出多少个“-”?
#include <stdio.h>#include <sys/types.h>#include <unistd.h> int main(void){ int i; for(i=0; i<2; i++){ fork(); printf("-"); } return 0;}
答案是输出8个“-”。首先说肯定至少输出6个“-”,因为父进程会调用两次fork,创建两个子进程,之后又会创建一个进程,所以会输出6个“-”。给出下图,会让结果更明显:
另外两个“-”是因为:printf(“-”);语句有buffer,所以,对于上述程序,printf(“-”);把“-”放到了缓存中,并没有真正的输出,在fork的时候,缓存被复制到了子进程空间,所以,就多了两个,就成了8个,而不是6个。
文件共享
内核使用三种数据结构表示打开的文件,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。
(1)每个进程在进程表中都有一个记录项,记录项中包含有一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项。与每个文件描述符相关联的是:
- 文件描述符标志(close_on_exec)。
- 指向一个文件表项的指针
- 文件状态标志(读、写、添写、同步和非阻塞等)。
- 当前文件偏移量。
- 指向该文件v节点表项的指针。
如下是打开文件的内核数据结构:
fork的一个特性是父进程的所有打开文件描述符都被复制到子进程中,父、子进程的每个相同的打开描述符共享一个文件表项。
考虑下述情况,一个进程具有三个不同的打开文件,它们是标准输入、标准输出和标准出错。在从fork返回时,打开文件的内核数据结构如下:
这种共享文件的方式使父、子进程对同一个文件使用了一个文件偏移量。考虑下述情况:一个进程fork了一个子进程,然后等待子进程终止。假定,作为普通处理的一部分,父、子进程都向标准输出进行写操作。如果父进程的标准输出已重定向(很可能是由shell实现的),那么子进程写到该标准输出时,他将更新与父进程共享的该文件的偏移量。在我们所考虑的例子中,当父进程等待子进程时,它将更新与父进程共享的该文件的偏移量。当父进程等待子进程时,子进程写到标准输出,而在子进程终止后,父进程也写到标准输出上,并且知道其输出会添加在子进程所写数据之后。如果父子进程不同想同一个文件偏移量,这种形式的交互就很难实现。
用fork函数产生的子进程与父进程的区别:
- fork的返回值。
- 进程ID不同
- 两个进程具有不同的父进程ID。
- 子进程的tms_utime、tms_stime、tms_cutime和tms_cstime均被设置为0.
- 父进程设置的文件锁不会被子进程继承。
- 子进程的未处理的闹钟被清除。
- 子进程的未处理信号集设置为空集。
fork有下面两种用法:
- 一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理该请求。父进程则继续等待下一个服务请求到达。
- 一个进程要执行一个不同的程序。这对于shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec。
vfork函数的调用序列和返回值与fork相同,但两者的语义不同。
vfork用于创建一个新进程,而该新进程的目的是exec一个新程序。vfork和fork一样都是创建一个子进程,但是它们的不同之处:
- vfork并不将父进程的地址空间复制到子进程中,因为子进程会立马调用exec(或exit),于是也就不会存访该地址空间。所以在子进程调用exec或exit之前,它都在父进程的地址空间中运行。
- vfork保证子进程先运行,在子进程调用exec或exit后吗,父进程才可能被调度运行。
- 《UNIX环境高级编程》学习笔记——进程控制(一)
- Unix环境高级编程学习笔记(五) 进程控制
- UNIX环境高级编程学习笔记(九)进程控制
- 《UNIX环境高级编程》学习笔记——进程控制(二)
- Unix高级环境编程—进程控制(一)
- 《UNIX环境高级编程》学习笔记——进程环境
- 《UNIX环境高级编程》学习笔记一之进程环境
- linux进程控制(一)--unix环境高级编程读书笔记
- 《unix高级环境编程》进程控制——进程ID
- 《unix高级环境编程》进程控制——创建进程
- 《unix高级环境编程》进程控制——进程等待
- 《unix高级环境编程》进程控制——进程时间
- 《unix高级环境编程》进程控制——进程ID
- 《unix高级环境编程》进程控制——创建进程
- 《unix高级环境编程》进程控制——进程等待
- 《unix高级环境编程》进程控制——进程时间
- UNIX环境高级编程——进程(一)
- Unix环境高级编程学习笔记(四) 进程环境
- Python 简单数据备份脚本
- K-邻近算法
- 汉诺塔:递归
- 利用过滤器filter处理乱码
- ssa/ass字幕格式全解析
- 《UNIX环境高级编程》学习笔记——进程控制(一)
- 有没有一句深刻的话改变了你,并让你一直付诸实践至今
- MIPS汇编
- 字符串反转 -- java实现
- 黑马程序员之java编程基础2
- 递归调用的确定
- C++ 多线程同步相关
- 反思:IT部门在企业中的位置,IT人的地位,IT的价值
- 从程序员到技术总监,分享10年开发经验