开发者社区> 可口也可樂、> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Linux进程控制(1)

简介: Linux进程控制(1)
+关注继续查看

零、前言


前篇我们讲解学习了关于进程的概念知识,本章主要讲解关于进程的控制,深入学习进程


一、进程创建


1、fork函数


  • 概念:


在linux中fork函数从已存在进程中创建一个新进程(子进程),而原进程为父进程


  • fork函数原型:


pid_t fork(void);


注意:

使用fork()函数需要包含头文件<unistd.h>;pid_t类型需要包含头文件<sys/types.h>


fork成功后对子进程返回0,对父进程返回子进程id,fork出错返回-1


内核视角看待fork:

进程调用fork,内核分配新的内存块和内核数据结构给子进程


将父进程部分数据结构内容拷贝至子进程(例如PCB进程控制块,进程地址空间,页表等)


添加子进程到系统进程列表当中,当fork返回后开始调度器调度进程


示图:


fork后执行问题:

当一个进程调用fork之后,父子进程共享同一份代码,也就是说整个代码父子进程都可以看到,但是此时父子进程的执行位置都是相同的,也就是说fork返回后子进程也是往fork之后的代码执行(并非再从头执行)


示例:


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

int main()
{
    printf("Before fork: pid is %d\n", getpid());
    pid_t pid=fork();
    if (pid== -1 )//fork错误
    {
        perror("fork fail");
        exit(1);
    }
    printf("After fork:pid is %d, fork return %d\n", getpid(), pid);
    sleep(1);
    return 0;
}


结果:


示图:


2、fork返回值


返回值:

fork成功对子进程返回0,对父进程返回子进程的pid


写时拷贝


概念:

fork成功之后父子代码共享,当父子不写入数据时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本


为什么数据要进行写时拷贝:

进程具有独立性,多进程运行,需要独享各种资源,多进程运行期间互不干扰,不能让子进程的修改影响到父进程


为什么不在创建子进程的时候就进行数据的拷贝:

子进程不一定会使用父进程的所有数据,并且在子进程不对数据进行写入的情况下,没有必要对数据进行拷贝,我们应该按需分配,在需要修改数据的时候再分配(延时分配),这样可以高效的使用内存空间,提高fork效率,以及fork的成功率


代码会不会进行写时拷贝:

90%的情况下是不会的,但这并不代表代码不能进行写时拷贝,例如在进行进程替换的时候,则需要进行代码的写时拷贝


示图:


fork函数为什么要给子进程返回0,给父进程返回子进程的PID:


一个父进程可以创建多个子进程,而一个子进程只能有一个父进程。因此,对于子进程来说,父进程是不需要被标识的;而对于父进程来说,子进程是需要被标识的,因为父进程创建子进程的目的是让其执行任务的,父进程只有知道了子进程的PID才能很好的对该子进程进行深入操作


为什么fork存在“两个”返回值:


父进程创建子进程时,子进程以父进程为模板构建进程,代码数据父子共享,返回时也是父子进程进行修改数据时,由页表发现该数据是父子进程共享的,所以系统会找到另一个物理空间进行拷贝数据,拷贝数据后再修改数据,达到数据各有一份互不干扰的目的,保证进程的独立性

3、fork用法


我们创建子进程并不是为了父进程执行一样的代码,而是为了使父子进程同时执行不同的代码段


例如:父进程等待客户端请求,生成子进程来处理请求


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

int main()
{
    pid_t id=fork();//创建子进程
    if(id==0)
    {
        //child
        int cnt=0;
        while(1)
        {
            printf("I am child: pid:%d ppid:%d\n",getpid(),getppid());
            sleep(1);
            if(cnt==8)
                break;
            cnt++;
        }   
        exit(1);//终止进程
    }
    else if(id>0)
    {
        //father
       int cnt=0;
        while(1)
        {
            printf("I am father: pid:%d ppid:%d\n",getpid(),getppid());
            sleep(1);
            if(cnt==8)
                break;
            cnt++;
        }   
    }
    return 0;
}


image.png


  • 用法2:fork返回后调用exec函数替换进程


注:在下文有着重讲解


4、fork失败


fork本质就是向系统要资源,当某个资源不够时则会发生fork失败


  • 失败原因:


1.系统中有太多的进程



2.实际用户的进程数超过了限制



用法1:fork返回后分流执行不同代码


示例:


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Linux进程控制(2)
Linux进程控制(2)
36 0
Linux进程控制(3)
Linux进程控制(3)
34 0
Linux 技巧:让进程在后台可靠运行的几种方法
Linux 技巧:让进程在后台可靠运行的几种方法 我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。
752 0
Linux 技巧:让进程在后台可靠运行的几种方法
原文地址: http://www.ibm.com/developerworks/cn/linux/l-cn-nohup/ 申 毅, 软件工程师, IBM 中国软件开发中心 简介: 想让进程在断开连接后依然保持运行?如果该进程已经开始运行了该如何补救? 如果有大量这类需求如何简化操作? 我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。
1078 0
170
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载