传统的fork()系统调用直接把所有的资源复制给新创建的进程。这种实现过于简单并且效率低下,因为它拷贝的数据或许可以共享。更糟糕的是,如果新进程打算立即执行一个新的映像,那么所有的拷贝都将前功尽弃。
Linux的fork()使用写时拷贝 (copy- on-write)页实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进程拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。这种技术使地址空间上的页的拷贝被推迟到实际发生写入的时候。在页根本不会被写入的情况下---例如,fork()后立即执行exec(),地址空间就无需被复制了。fork()的实际开销就是复制父进程的页表以及给子进程创建一个进程描述符。下列程序可证明写时拷贝:
#include <stdio.h>
#include <sched.h>
int data = 10;
int child_process()
{
printf("Child process %d, data %d\n",getpid(),data);
data = 20;
printf("Child process %d, data %d\n",getpid(),data);
while(1);
}
int main(int argc, char* argv[])
{
if(fork()==0) {
child_process();
}
else{
sleep(1);
printf("Parent process %d, data %d\n",getpid(), data);
while(1);
}
}
运行结果
Child process 6427, data 10
Child process 6427, data 20
Parent process 6426, data 10
第 1个Child process 6427, data 10是因为子进程创建时task_struct的mm直接拷贝自parent的mm;第2个Child process 6427, data 20是因为子进程进行了“写时拷贝”,有了自己的data;第3个Parent process 6426, data 10输出10是因为子进程的data和父进程的data不是同一份。
如果把上述程序改为:
#include <stdio.h>
#include <sched.h>
#include <stdlib.h>
int data = 10;
int child_process()
{
printf("Child process %d, data %d\n",getpid(),data);
data = 20;
printf("Child process %d, data %d\n",getpid(),data);
while(1);
}
int main(int argc, char* argv[])
{
void **child_stack;
child_stack = (void **) malloc(16384);
clone(child_process, child_stack, CLONE_VM|CLONE_FILES|CLONE_SIGHAND, NULL);
sleep(1);
printf("Parent process %d, data %d\n",getpid(), data);
while(1);
}
运行结果将是
Child process 6443, data 10
Child process 6443, data 20
Parent process 6442, data 20
由于使用了CLONE_VM创建进程,子进程的mm实际直接指向父进程的mm,所以data是同一份。改变父子进程的data都会互相看到。
转自http://linux.chinaitlab.com/system/775850.html
分享到:
相关推荐
linux C语言,编程实现父子进程同时拷贝文件,各复制一半
当父进程发现请求数 >= 子进程数时,父进程创建新的子进程,并把子进程数加1(当然子进程数有个预先上限);当父进程发现子进程数大于请求数加1时,父进程杀死多余的子进程。 总的来说,思想是让子进程accept并处理...
fork( )只是将父进程的用户级上下文拷贝到新进程中,而exec( )系列可以将一个可执行的二进制文件覆盖在新进程的用户级上下文的存储空间上,以更改新进程的用户级上下文。exec( )系列中的系统调用都...
Linux通过fork创建子进程与创建线程之间是有差别的:fork创建出该进程的一份拷贝,这个新进程拥有自己的变量和自己的PID,它的时间调度是独立的,它的运行差点儿全然独立于父进程。 进程能够看成一个资源的...
本文实例讲述了Python实现Linux下守护进程的编写方法,分享给大家供大家参考,相信对于大家的Python...子进程从父进程继承了多个值的拷贝,比如全局变量和环境变量。两个进程唯一的区别就是fork的返回值。child(子)进
在Linux中,通过fork创建子进程,子进程通过exit()系统调用终结进程并将其占用的资源释放掉,此时子进程被设置为僵死状态,父进程可以通过wait()或waitpid()系统调用查询子进程是否终结。 内核把进程的列表存放...
fork作用为创建一个子进程,在使用了fork命令后,内核会分配新的内存块和数据结构给子进程,并且将父进程的部分数据结构内容拷贝到子进程,最后再将子进程添加到系统进程列表中,添加完成后fork返回,开始调度。...
getppid(取得父进程的进程识别码) 107 11.14 107 getpriority(取得程序进程执行优先权) 107 11.15 108 nice(改变进程优先顺序) 108 11.16 108 on_exit(设置程序正常结束前调用的函数) 108 11.17 109 setpgid...
4. explorer-------打开资源管理器 5. logoff---------注销命令 6. shutdown-------60秒倒计时关机命令 7. lusrmgr.msc----本机用户和组 8. services.msc---本地服务设置 9. oobe/msoobe /a----检查XP是否激活 ...
易语言5.1 相对于易语言5.0更新说明: ... 修改XML解析支持库,增加写出CDATA数据功能,解决解析XML时错误的丢弃换行和TAB字符的BUG,解决读取节点值时对CDATA数据进行转义处理的BUG。 20. 修改扩展界面支持库...
器的进程中将该进程结束,而后再次运行就没问题了,当然先关闭Qt Creator, 而后再重新打开,这样也能解决问题。 如果把程序改为这样: #include #include "widget.h" #include "mydlg.h" int main(int argc, char ...
含有下列参数的 bootcfg 命令仅在使用故障恢复控制台时才可用。可在命令提示符下使用带有不同参数的 bootcfg 命令。 用法: bootcfg /default 设置默认引导项。 bootcfg /add 向引导列表中添加 Windows...