有用的"Copy-On-write",写时复制
写时复制和写时拷贝是一个意思
写时复制是一种策略,并不是Linux独有的,如果你正在设计某个系统架构,也可以参考这种思想。
写时复制的英文解释如下
Copy-on-write (sometimes referred to as "COW") is an optimization strategy used in computer programming.
写时复制是计算机的一种优化策略,也可以说是优化机制,是计算机的优化策略并没有错,但是这种策略是人想出来的。
The fundamental idea is that if multiple callers ask for resources which are initially indistinguishable, you can give them pointers to the same resource.
它的基本思想是,如果有多个调用「callers」,「也可以说是多个进程,多个线程,Linux里面只关心任务就好了」请求同一个难以区分的资源,你可以让他们指向同一个资源指针。
This function can be maintained until a caller tries to modify its "copy" of the resource, at which point a true private copy is created to prevent the changes becoming visible to everyone else.All of this happens transparently to the callers.
直到有其中一个调用者,试图更改这个两个进程都指向的资源,系统才会分配一个真正的资源「可以认为是物理地址」给这个调用者。这个过程对所有人可见。
The primary advantage is that if a caller never makes any modifications, no private copy need ever be created.
如果调用方,也就是拥有相同资源指针的两个进程,都不对资源进行修改,那么就不需要生产一个副本资源。
写时复制的缩写是「COW,奶牛」,但是实际上它跟奶牛没有任何关系。
举个例子说明
假设你是一个酒店老板,马云和任正非在你们酒店订了2020年11月20号的房间,你当时看到酒店还没有住满,所以就给他们下发了一个订购成功的返回值。
如果是程序,在内存充分的情况下,创建进程也就成功了。
然后,你其实不需要马上给马云和任正非安排具体的房间,因为他们俩都还没有到酒店开房。
假设晚上他们过来开房了,你就需要给他们开辟这个房间「也可以认为是资源」,给他们晚上做他们想做的事情。
如果他们一直都不来,那你就不用给他们开房,也就不实际占用你的房间。
fork()函数和写时复制
fork()函数是一个神奇的函数,调用一次,会返回两次,在这个过程中子进程和父进程是共享一个内存空间的。
#include
#include
int main()
{
int pid = fork();
if(pid == -1){
return (-1);
}
if(pid > 0){
printf("Hi,Father Pid:%d\n",getpid());
return (0);
} else {
printf("Hi,Child Pid:%d\n",getpid());
return (0);
}
}
-- 程序输出:
weiqifa@bsp-ubuntu1804:~/linux$ gcc -o copy copy-for-write.c
weiqifa@bsp-ubuntu1804:~/linux$ ./copy
Hi,Father Pid:36320
Hi,Child Pid:36321
-- 然后我加入一个资源
#include
#include
int main()
{
char c = 'a';
int pid = fork();
if(pid == -1){
return (-1);
}
if(pid > 0){
c = 'v';
printf("Hi,Father Pid:%d &c:%p c:%c\n",getpid(),&c,c);
return (0);
} else {
printf("Hi,Child Pid:%d &c:%p c:%c\n",getpid(),&c,c);
return (0);
}
}
-- 程序输出:
weiqifa@bsp-ubuntu1804:~/linux$ gcc -o copy copy-for-write.c && ./copy
Hi,Father Pid:36518 &c:0x7ffc41acae93 c:v
Hi,Child Pid:36519 &c:0x7ffc41acae93 c:a
我们可以看到,父进程中我们对资源 c 进行了修改,并打印了资源的地址和值,然后我们在子进程中也打印资源的值。
可以看到,父进程先执行修改 c 的值,并打印 c 的值 是 v
子进程运行,打印 c 的值,c 的值是 原理的初始化值 a 。
也就是说这个过程发生了写时复制,在父进程种给 c 分配了物理内存区别于子进程。
创建进程没有发生写时拷贝的情况
没有发生写时复制的情况
发生了写时复制的情况