多进程---fork()

fork() 函数的使用很简单。fork() 函数被调用一次,但返回两次。两次返回的区别是:子进程的返回值是 0,而父进程的返回值则是新子进程的进程 ID。故我们可以通过判断返回值来区分父子进程。如果不做判断,fork() 后的代码父子进程会各执行一遍。

 一个进程调用 fork() 函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。所以 fork() 的使用还是比较耗资源的。

Linux 的 fork() 使用是通过写时拷贝 (Copy- On-Write,COW技术) 实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进程拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。(这段是从网上看到某高手写的。但是我用我的方式测试了一下,结果让我比较费解。看下面)

代码

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>

int num1 = 0;

int main()
{
    int num2 = 0;

    printf("原始地址: &num1=%X &num2=%X\n",&num1,&num2);

    pid_t pid = fork();
    /* fork返回进程号,是非负数 */
    if(pid < 0)
    {
        perror("fork");
        return -1;
    }
    /* 子进程 */
    if(pid == 0)
    {
        printf("写前地址:&num1=%X &num2=%X\n",&num1,&num2);
        num1 = 1;
        printf("写后地址:&num1=%X &num2=%X\n",&num1,&num2);
        printf("子进程:%d num1=%d num2=%d\n",getpid(),num1,num2);
    }
    /* 父进程 */
    else if(pid > 0)
    {
        printf("写前地址:&num1=%X &num2=%X\n",&num1,&num2);
        num2 = 2;
        printf("写后地址:&num1=%X &num2=%X\n",&num1,&num2);
        printf("父进程:%d num1=%d num2=%d\n",getpid(),num1,num2);
    }
    return 0;
}
[lingyun@manjaro study]$ gcc study.c 
[lingyun@manjaro study]$ ./a.out
原始地址:&num1=180AB054 &num2=DEB5D8B0
写前地址:&num1=180AB054 &num2=DEB5D8B0
写后地址:&num1=180AB054 &num2=DEB5D8B0
父进程:3051 num1=0 num2=2
写前地址:&num1=180AB054 &num2=DEB5D8B0
写后地址:&num1=180AB054 &num2=DEB5D8B0
子进程:3052 num1=1 num2=0

可以看到结果,父子进程对变量的修改是互不影响的,可以证明各自的地址空间是独立的。但是我实在不明白为啥在写操作过后,父子进程中的 num1 和 num2 地址仍然没有变化。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值