【Linux】六、进程控制

进程创建

fork函数的认识

#include

pid_t fork(void)

#include 
#include 

int main()
{
    printf("我是父进程!\n");
    pid_t id = fork();
    if(id < 0)
    {
        printf("创建子进程失败\n");
        return 1;
    }
    else if
    {
        //子进程
        while(1)
        {
            printf("我是子进程:pid: %d, ppid: %d\n",getpid(),getppid());
            sleep(1);
        }
    }
    else
    {
        //父进程
        while(1)
        {
            printf("我是子进程:pid: %d, ppid: %d\n",getpid(),getppid());
            sleep(1);
        }
    }
    return 0;
}

请描述一下,fork创建子进程,操作系统都做了什么?

fork创建子进程就是系统里多了一个进程,也就是进程=内核数据结构+进程代码和数据;一般从磁盘中来,也就是C\C++程序加载后的结果;分配新的内存块和内核数据结构给子进程;将父进程部分数据结构内容拷贝到到子进程;添加子进程到系统进程列表当中,fork返回开始调度器调度;

创建子进程给子进程分配对应的内核结构,理论上子进程也要有自己的代码和数据,但是一般子进程没有加载的过程,也就是说子进程没有自己的代码和数据,所以子进程只能使用父进程的代码和数据;

代码:都是不可以被写的,只能读取,所以父子进程共享没有问题;

数据:可能被修改,所以必须分离;

当想要修改数据时,有两种方案

1、创建进程时,就直接拷贝分离,也就是将父进程给子进程拷贝一份,但这样做有一个问题,可能拷贝子进程根本不会用到的数据空间,即使用到了也就是读取;

#include 
#include 

int main()
{
    char *str = "aaa";
    char *str1 = "aaa";

    printf("%p\n", str);
    printf("%p\n", str1);
    return 0;
}

此时打印出来的结果地址是相同的,编译器编译程序的时候都知道使用这种方式节省空间,所以操作系统在创建子进程的时候,不需要将不会被访问的或者只会读取的数据,拷贝出一份;那么什么样的数据值的被拷贝呢?将来会被父或子进程写入的数据;一般来说,即便是操作系统也无法提前知道哪些空间可能会被写入,并且即便是提前拷贝了可能也不会立刻使用,所以操作系统选择了写时拷贝技术将父子进程的数据进行分离;

2、写时拷贝;

fork之后是所有的代码共享,不是fork之后的代码共享;

原因:首先,当代吗进行汇编后,会有很多行代码,而且每行代码加载到内存后都有对应的地址;其次,因为进程随时可能被中断(可能没有执行完),下次回来,还必须从之前的位置继续运行,就要求CPU必须随时记录下当前进程执行的位置,所以,CPU内有对应的寄存器数据,用来记录当前进程执行的位置,寄存器叫做EIP,也叫做pc(point code)指针,程序计数器;寄存器在CPU内只有一份,但是寄存器的数据,可以有很多份,而这个数据也就是上下文数据,而这个上下文数据,通过写时拷贝给子进程,父子进程各自调度,各自会修改自己的EIP,但是此时子进程已经认为自己的EIP起始值就是fork之后的代码;

你可能感兴趣的:(Linux,linux,算法,运维)