Linux应用学习——多进程

news2024/10/2 14:23:19

进程

在这里插入图片描述

  • 当一个进程正常终止时可以通过int atexit(void(*function)(void))注册进程终止处理函数

PART1——进程相关概念

​ 进程是一个动态的过程,而非一个静态的文件,是程序的一次运行过程,当应用程序被加载到内存中运行之后才能称为一个进程

1.1 进程号

每一个进程都有一个进程号(PID),进程号是一个正数,用于唯一标识一个进程。

在应用程序中可以

  • 通过pid_t getpid(void)来获取进程号
  • 通过pid_t getppidd(void)获取父进程的进程号

1.2 进程环境变量

每一个进程都有一组与其相关的环境变量,这些环境变量是由键值对组成的

在应用程序中可以

  • 通过申明extern char **environ就可以使用environ[]来获取环境变量
  • 通过char *getenv(const char *name)来获取指定环境变量
  • 通过int putenv(char *string)添加环境变量
  • 通过int setenv(const char *name,const char *value,int overwrite)添加或者修改环境变量
    • overwrite为0,不修改原有值,非零,则覆盖
  • 通过unsetenv(const char *name)移除环境变量
  • 通过int clearenv(void)清空环境变量

1.3 进程的内存布局

  • 代码段具有只读属性,代码段是可以共享的,即使在多个进程也可以运行同一段程序
  • 初始化数据段已经初始化的全局变量和静态变量,当程序加载到内存中是,从可执行文件中读取这些变量值
  • 未初始化数据段未初始化的全局变量和静态变量,也称为bss段,在程序开始执行之前,系统会将本段的所有内存初始化为0,可执行文件未给bss段分配存储空间,只记录bss段的位置及其所需大小,直到程序运行时,由加载器分配这一段的内存空间
  • 函数内部的局部变量以及函数调用所需保存的信息都放在栈区中,函数传递的实参UI及函数的返回值也存放在此
  • 可在运行时动态进行内存分配的一块区域
  • 可以通过size+二进制可执行文件来查询文本段、数据段和bss段的段大小

1.4 进程的虚拟地址空间

32位的系统,每个进程的逻辑地址空间为4GB,但是实际的物理地址空间并没有那么大,所以需要通过一个MMU系统来进行地址映射

为什么要用虚拟地址?

  • 内存使用效率低
  • 进程地址空间不隔离
  • 无法确定程序的链接地址
  • 进程与进程、进程与内核之间相互隔离
  • 两个或更过的进程能够共享内存
  • 便于实现内存保护机制
  • 无需关心链接地址

1.5 进程的诞生与终止

1.5.1 诞生

  • 一个进程可以通过 fork()或 vfork()等系统调用创建一个子进程,一个新的进程就此诞生
  • 上图中进程号为 1 的进程便是所有进程的父进程,通常称为 init 进程,它是 Linux 系统启动之后运行的第一个进程,它管理着系统上所有其它进程, init 进程是由内核启动,因此理论上说它没有父进程

1.5.2 终止

  • 正常终止:exit() _exit() _Exit()

  • 异常终止:调用abort异常终止,或者,接收到某些信号导致异常终止

  • exit()函数和 exit()函数的 status 参数定义了进程的终止状态,父进程可以调用 wait()函数以获取该状态。

  • exit()函数会比_exit()会多做一些事情,包括执行终止处理函数、刷新 stdio 流缓冲以及调用_exit(),在前面曾提到过,在我们的程序当中,父、子进程不应都使用 exit()终止,只能有一个进程使用 exit()、而另一个则使用_exit()退出,当然一般推荐的是子进程使用_exit()退出、而父进程则使用 exit()退出。

1.6 进程的状态与关系

进程的状态分为:

  1. 就绪态
  2. 运行态
  3. 僵尸态
  4. 可中断睡眠状态
  5. 暂停态

PART2——创建进程

应用程序可以

  • 通过pid_t fork(void)创建一个新的进程,调用fork函数的进程称为父进程
  • 每个进程都会从fork函数的返回出继续执行,会导致调用fork返回两次值,可以通过返回的两个值来区分子进程(返回值为0)还是父进程(返回值非零),如果返回-1,则创建失败
  • fork()调用成功后,子进程、父进程各自在自己的进程空间中运行。事实上,子进程是父进程的一个副本, 譬如子进程拷贝了父进程的数据段、堆、栈以及继承了父进程打开的文件描述符,父进程与子进程并不共享这些存储空间,这是子进程对父进程相应部分存储空间的完全复制,
  • 执行 fork()之后,每个进程均可修改各自的栈数据以及堆段中的变量,而并不影响另一个进程。
  • 子进程是父进程的一个副本,但是对于程序代码段(文本段)来说, 两个进程执行相同的代码段,
  • 代码段是只读的, 也就是说父子进程共享代码段,在内存中只存在一份代码段数据。
  • 子进程拷贝了父进程的文件描述符表,使得父、子进程中对应的文件描述符指向了相同的文件表, 也意味着父、子进程中对应的文件描述符指向了磁盘中相同的文件,因而这些文件在父、子进程间实现了共享

fork使用场景

  • 父进程希望子进程复制自己(父进程等待客户端的请求,当接收到请求,创建子进程去处理)
  • 一个进程要执行不通的程序(app1中调用app2)

fork之后,父进程和子进程运行的先后顺序是随机的,可以通过信号来阻塞,之后再释放来区分先后

static void sig_handler(int sig)
{
    //deal with signal
}

int main(void)
{   
    struct sigation sig = {0};

    sigset_t wait_mask;

    sigemptyset(&wait_mask);
    sig.sa_handler=sig_handler;
    sig.sa_flags=0;
    if (sigation(SIGUSR1,&sig,NULL))
    {
        perror("error");
        exit(-1);
    }
    
    switch (fork())
    {
    case -1:
        perror("error");
        exit(-1);
    case 0://子进程
        sleep(2);
        kill(getppid(),SIGUSR1);
        _exit(0);
    
    default://父进程
        if (-1 != sigsuspend(&wait_mask))
        {
            exit(-1);
        }
        exit(0);
    }
}

PART3——监视子进程

3.1 wait

  • 应用程序通过调用pid_t wait(int *statue)等待进程的任一子进程终止,同时获取子进程的终止状态信息
  • 调用 wait()函数,如果其所有子进程都还在运行,则 wait()会一直阻塞等待,直到某一个子进程终止;
  • 如果进程调用 wait(),但是该进程并没有子进程, 也就意味着该进程并没有需要等待的子进程, 那 么 wait()将返回错误,也就是返回-1、并且会将 errno 设置为 ECHILD
  • 如果进程调用 wait()之前, 它的子进程当中已经有一个或多个子进程已经终止了,那么调用 wait()
    也不会阻塞。 wait()函数的作用除了获取子进程的终止状态信息之外,更重要的一点,就是回收子
    进程的一些资源

3.2 waitpid

  • 应用程序可以通过调用pid_t waitpid(pid_t pid,int *status,int options)来等待指定进程终止

3.3 僵尸进程与孤儿进程

  • 父进程先于子进程结束,此时子进程就变成一个孤儿进程。所有的孤儿进程都自动成为init(PID=1)进程的子进程
  • 当子进程结束,而父进程还没有回收子进程的资源时,此时的子进程被称为僵尸进程

SIGCHLD信号

  • 当父进程的某个子进程终止时,父进程会受到SIGCHLD信号
  • 当父进程的某个子进程因收到信号而停止或者回复时,内核也可能向父进程发送该信号

PART4——调用新程序

4.1 exec族

系统调用 execve()可以将新程序加载到某一进程的内存空间,通过调用 execve()函数将一个外部的可执行文件加载到进程的内存空间运行,使用新的程序替换旧的程序,而进程的栈、数据、以及堆数据会被新程序的相应部件所替换,然后从新程序的 main()函数开始执行

  1. int execl(const char *path,const char *arg,...)
  2. int execlp(const char *file,const char *arg,...)
  3. int execle(const char *path,const char *arg,...)
  4. int execv(const char *path,char *const argv[])
  5. int execvp(const char *file,char *const argv[])
  6. int execvpe(const char *file,char *const argv[],char *const envp[])

int execve(const char *filename,char *const argv[],char *const envp[])

  • filename指向需要载入当前进程空间的新程序的路径名
  • argv传递给新程序的命令行参数
  • envp指向了新程序的环境变量列表
  • 调用成功永不返回,一旦函数返回,就表明发生了错误

4.2 system

  • int system(const char *command)

使用示例:

system("ls -la")

进程间通信

1.管道

  • 普通管道
  • 流管道
  • 有名管道

2.信号

3.消息队列

4.信号量

5. 共享内存

6.套接字

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/397611.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode——排序链表】

文章目录排序链表二、解题思路:二.实现的代码总结:排序链表 一道链表排序题,链接在这里 二、解题思路: 解题思路:使用归并排序(用递归实现) 第一步:先找到链表的中间节点 第二步…

百分之九十的人不知道的退税秘诀

为什么会有退税和补税? 公司在帮我们进行个人所得税申报的时候,个人所得税是按月或者按季度预扣预缴的,税款会在每个月或季度的收入中扣除一定的比例。在年度个人所得税汇缴清算的时候,如果实际年度收入与预扣预缴的税款不符&…

【Spring 深入学习】配置DI 以及IOC的多种方式

配置DI 以及IOC的多种方式 1. 概述 防止将来遗忘&#xff0c;记录下DI等配置方式。从xml 配置文件 以及注解的方式来配置下DI 2. XML 方式 2.1 通过bean 依赖注入 xml 配置 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http:/…

Zeek安装、使用与压力测试

Zeek安装与压力测试Zeek安装、简单使用与压力测试环境Zeek安装zeek简单运行安装PF_RING修改Zeek配置文件&#xff0c;使用PF_RING&#xff0c;实现集群流量压力测试查看zeek日志Zeek安装、简单使用与压力测试 科研需要&#xff0c;涉及到Zeek的安装、使用和重放流量压力测试评…

【牛客刷题专栏】0x0F:JZ7 重建二叉树(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转)&#xff0c;它登陆后会保存刷题记录进度&#xff0c;重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏&#xff1a;个人CSDN牛客刷题专栏。 题目来自&#xff1a;牛客/题库 / 在线编程 / 剑指offer&#xff1a; 目录前言问题…

VKL060 SSOP24超低功耗/抗干扰15*4 LCD液晶段码驱动IC,适用于传感器/数字压力表

产品型号&#xff1a;VKL060产品品牌&#xff1a;永嘉微电/VINKA封装形式&#xff1a;SSOP24产品年份&#xff1a;新年份原厂&#xff0c;工程服务&#xff0c;技术支持&#xff01;VKL060概述:VKL060是一个点阵式存储映射的LCD驱动器&#xff0c;可支持最大60点&#xff08;15…

【ROS学习笔记13】ROS中的TF坐标变换

【ROS学习笔记13】ROS中的TF坐标变换 文章目录【ROS学习笔记13】ROS中的TF坐标变换前言1. 静态坐标变换2. 动态坐标变换3. 多坐标变换4. 坐标系关系查看5. TF坐标变换实操Reference写在前面&#xff0c;本系列笔记参考的是AutoLabor的教程&#xff0c;具体项目地址在 这里 前言…

sqli-labs靶场实战

sqli-labs靶场实战 &#xff08;手工&#xff09;SQL注入基本步骤&#xff1a; 第一步&#xff1a;注入点测试 第二步&#xff1a;查询字段数 第三步&#xff1a;判断回显位 第四步&#xff1a;查询数据库的基本信息 第五步&#xff1a;爆数据库名 第六步&#xff1a;爆数据库…

ROS云课使用CoCubeSim案例

源码压缩包&#xff1a;https://gitcode.net/ZhangRelay/cocubesim打开蓝桥ROS云课&#xff1a;下载cocubesim压缩包&#xff1a;https://gitcode.net/ZhangRelay/cocubesim.git注意文件路径&#xff0c;home文件夹下的code文件夹里面。解压缩&#xff1a;tar -xf cocubesim/co…

黑马Linux笔记03【su、sudo、groupadd、useradd、usermod、userdel、getent、chmod、chown】

资源 视频地址&#xff1a;黑马-新版Linux快速入门到精通资源下载&#xff1a;https://pan.baidu.com/s/1zExrsk09QVm3mpqaPTqe_g?pwd6666&#xff0c;提取码&#xff1a;6666笔记 黑马Linux笔记01【安装VMware Workstation、安装CentOS7、远程连接Linux系统、Win10配置WSL(Ub…

机器学习算法: Logistic 回归 详解

动动发财的小手&#xff0c;点个赞吧&#xff01; 1. 导读 逻辑回归是在因变量为二元时进行的回归分析。它用于描述数据并解释一个因二元变量与一个或多个名义、有序、区间或比率水平变量之间的关系。二元或二项式 Logistic 回归可以理解为处理其中因变量的观察结果只能是二元的…

Mac电脑,python+appium+安卓模拟器使用步骤

1、第一步&#xff0c;环境搭建&#xff0c;参考这位博主的文章&#xff0c;很齐全 https://blog.csdn.net/qq_44757414/article/details/128142859 我在最后一步安装appium-doctor的时候&#xff0c;提示权限不足&#xff0c;换成sudo appium-doctor即可 2、第二步&#xff0…

Discuz X3.1 QQ互联登陆报错解决方法

安装X3.1后QQ互联登陆出现(1054) Unknown column conuintoken in field list&#xff0c;具体截图如下&#xff1a; 原因是用QQ登陆的时候是把你的账号信息写入数据表common_member_connect中的&#xff0c;而这个语句中有conuintoken 这个字段&#xff0c;但数据表common_mem…

【Java基础】10分钟看懂Java NIO

一、IO概述IO的操作方式通常分为几种:同步阻塞BIO、同步非阻塞NIO、异步非阳塞AIO1、在JDK1.4之前&#xff0c;我们建立网络连接的时候采用的是 BIO 模式。2、Java NIO(New IO或Non Blocking IO) 是从Java 1.4版本开始引入的一个新的IOAPI&#xff0c;可以替代标准的Java IO AP…

跨域问题解决方案

目录 1.同源策略 2.解决方案(后端) (1)在后端方法添加CrossOrigin (2)添加CORS过滤器 (3)实现WebMvcConfigure接口&#xff0c;重写addCorsMappings方法 3.解决方案(前端) (1)前端配置代理 1.同源策略 同源策略&#xff08;Same origin policy&#xff09;是一种约定&am…

代码随想录算法训练营day53 | 动态规划之子序列 1143.最长公共子序列 1035.不相交的线 53. 最大子序和

day531143.最长公共子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺序5.举例推导dp数组1035.不相交的线53. 最大子序和1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何…

【深入理解 线程池】

深入理解 线程池介绍源码学习线程池的类继承体系ThreadPoolExector核心数据结构核心配置参数线程池的执行流程如图&#xff1a;线程池的优雅关闭线程池的生命周期正确关闭线程池的步骤任务的提交过程分析任务的执行过程shutdonw() 与任务执行过程综合分析shutdonwNow() 与任务执…

python3.6 处理报错free(): invalid pointer

在运行脚本的时候遇到了这个报错&#xff0c;我在笔记本的win10 python3.7上正常运行&#xff0c;把程序考到服务器报了这个错&#xff0c;free(): invalid pointer 脚本里写了异常处理&#xff0c;用的是纯净的虚拟环境&#xff0c;所以我感觉问题是出在系统环境上 在网上搜…

Linux:tcp socket客户端和服务器端代码

服务器端代码&#xff1a; #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <arpa/inet.h> #include <sys/un.h> #include <sy…

手工数据采集耗时耗力?Smartbi数据填报实现数据收集分析自动化

企业在日常经营管理过程中&#xff0c;往往需要收集很多内外部的信息&#xff0c;清洗整理后再进行存储、分析、呈现、决策支持等各种作业&#xff0c;如何高效收集结构化数据是企业管理者经常要面对的问题。传统手工的数据采集方式不仅耗费了大量人力时间成本&#xff0c;还容…