linux系统编程-2、进程

2023-11-17

前言:Linux系统编程的基础系列文章,随着不断学习会将一些知识点进行更新,前期主要是简单了解和学习。

进程

进程运行状态

进程原语

fork

1、进程原语-fork

读时共享写时复制
只有进程空间的各段的内容要发生变化时(子进程或父进程进行写操作时,都会引起复制),才会将父进程的内容复制一份给子进程。

  • 在fork之后两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。

  • 即父子进程在逻辑上仍然是严格相互独立的两个进程,各自维护各自的参数,只是在物理上实现了读时共享,写时复制。

  • fork函数创建子进程后,内核只为新生成的子进程创建虚拟空间结构,它们来复制于父进程的虚拟空间结构,但是不为这些段分配物理内存,它们共享父进程的物理空间。

  • 直到父子进程中有更改相应段(用户空间中)的行为发生时,再为子进程相应的段分配物理空间。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
    pid_t pid;///< 调用一次返回两次,在父进程返回子进程的PID,在子进程返回0

    pid = fork();

    if (pid > 0) {
        printf("I am parent\n");
        while(1);
    }
    else if (pid ==0 ) {
        printf("I am child\n");
        while(1);
    }
    else {
        perror("fork");
        exit(1);
    }
}

调用命令查看当前运行进程

ps aux
kudio     10073  100  0.0   4352   652 pts/19   R+   18:06   0:13 ./fork-test
kudio     10074  100  0.0   4352    76 pts/19   R+   18:06   0:13 ./fork-test

可以发现两个进程均处于运行态,并且PID号相邻

进程相关函数

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

pid_t getpid(void);///< 返回调用进程的 PID号
pid_t getppid(void);///< 返回调用进程父进程的 PID号

uid_t getuid(void);///< 返回实际用户 ID
uid_t getuid(void);///< 返回有效用户 ID

gid_t getgid(void);///< 返回实际用户组 ID
gid_t getgid(void);///< 返回有效用户组 ID

exec族

2、进程原语-exec

execl

#include <stdio.h>
#include <unistd.h>

int main(void) {
    printf("hello\n");
    execl("/bin/ls", "ls", "-l", NULL);///< 进程代码段已经被 ls覆盖,并且是从 ls退出的
    printf("world\n");

    return 0;
}

通过以下代码进行测试:

#include <stdio.h>

int main(int argc, char *argv[]) {
    int i = 0;
    while (i < argc) {
        printf("%s\n", argv[i++]);
    }
    return 2;
}
gcc -g -Wall exec-child.c -o exec-child
#include <stdio.h>
#include <unistd.h>

int main(void) {
    printf("hello\n");
    execl("./exec-child", "./exec-child", "zhouyi", "kudio",  NULL);
    printf("world\n");

    return 0;
}
gcc -g -Wall exec-test.c -o exec-test

运行 ./exec-test, 得到结果如下:

hello
./exec-child
zhouyi
kudio

通过以下命令查看退出值

echo $?

可发现退出值为 2

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(void) {
    pid_t pid;

    pid = fork();
    if (pid == 0) {
        execl("/usr/bin/firefox", "firefox", "www.baidu.com", NULL);
    }
    else if (pid > 0) {
        while (1) {
            printf("I am parent.\n");
            sleep(1);
        }
    }
    else {
        perror("fork");
        exit(1);
    }
    return 0;
}
3、进程原语-exec-1

exec族区别

#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char *const envp[]); int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
  • 带有字母l(表示list)的exec函数

    • 要求将新程序的每个命令行参数都当作一个参数传给它
    • 命令行参数的个数是可变的,因此函数原型中有…,…中的最后一个可变参数应该是NULL,起sentinel的作用。
  • 带字母p(表示path)的exec函数

    • 第一个参数必须是程序的相对路径或绝对路径
  • 对于以e(表示environment)结尾的exec函数

    • 可以把一份新的环境变量表传给它。
  • 对于带有字母v(表示vector)的函数

    • 应该先构造一个指向各参数的指针数组,然后将该数组的首地址当作参数传给它,数组中的最后一个指针也应该是NULL,就像main函数的argv参数或者环境变量表一样。

事实上,只有execve是真正的系统调用,其他五个函数都调用execv。

4、进程原语-exec族之间的关系

wait/waitpid

#include <sys/types.h> 
#include <sys/wait.h>

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options); 
```C

一个进程释放需要释放两部分
* 用户空间代码释放
* PCB需要父进程回收释放

```C{.line-numbers}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int main(void) {
    int n = 10;
    pid_t pid;///< 调用一次返回两次,在父进程返回子进程的PID,在子进程返回0

    pid = fork();

    if (pid > 0) {

        while (1) {
            printf("I am parent: %d.\n", n++);
            printf("my pid = %d, my parent pid = %d.\n", getpid(), getppid());
            sleep(2);
        }
    }
    else if (pid == 0 ) {
            printf("I am child: %d.\n", n++);
            printf("my pid = %d, my parent pid = %d.\n", getpid(), getppid());
            sleep(4);
            return 0;
        }
    }
    else {
        perror("fork");
        exit(1);
    }
    return 0;
}
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
kudio      3424  0.0  0.0   4352   672 pts/2    S+   20:11   0:00 ./zombie-process
kudio      3425  0.0  0.0      0     0 pts/2    Z+   20:11   0:00 [zombie-process] <defunct>

可以发现父进程处于S+(Sleep)睡眠状态,而子进程处于Z+(Zombie)僵尸状态

  • return 0 的时候只是释放了用户空间代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int main(void) {
    pid_t pid, pid_child;
    pid = fork();

    if (pid > 0) {
        while (1) {
            printf("I am parent, my id is %d.\n", getpid());
            pid_child = wait(NULL);///< 回收僵尸子进程的 PCB
            printf("wait for child %d\n", pid_child);        
            sleep(2);
        }
    }
    else if (pid == 0 ) {
            printf("I am child, my id is %d.\n", getpid());
            sleep(4);
            return 0;
    }
    else {
        perror("fork");
        exit(1);
    }
    return 0;
}

通过 ps aux进行查看

USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
kudio      4040  0.0  0.0   4352   784 pts/2    S+   23:44   0:00 ./wait-test
kudio      4041  0.0  0.0   4352    76 pts/2    S+   23:44   0:00 ./wait-test

再次通过 ps aux进行查看

USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
kudio      4040  0.0  0.0   4352   784 pts/2    S+   23:44   0:00 ./wait-test

运行后得到如下:

I am parent, my id is 4040.
I am child, my id is 4041.
wait for child 4041
I am parent, my id is 4040.
wait for child -1

可以发现wait函数是个阻塞函数,父进程一直在等待回收子进程
如果没有子进程,则立即返回 -1

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux系统编程-2、进程 的相关文章

  • X11 模式对话框

    如何使用 Xlib 在 X11 中创建模式对话框 模态对话框是一个位于应用程序其他窗口之上的窗口 就像瞬态窗口一样 并且拒绝将焦点给予应用程序的其他窗口 在 Windows 中 当试图从模态窗口夺取焦点时 模态也会通过闪 烁模态窗口的标题栏
  • 在 Linux 上访问 main 之外的主要参数

    是否可以访问参数main在外面main 即在共享库构造函数中 在 Linux 上除了通过解析之外 proc self cmdline 您可以通过将构造函数放入 init array部分 功能在 init array 不像 init 使用相同
  • 找出 Linux 上的默认语言

    有没有办法从C语言中找出Linux系统的默认语言 有 POSIX API 可以实现这个功能吗 例如 我想要一个人类可读格式的字符串 即德语系统上的 German 或 Deutsch 法语系统上的 French 或 Francais 等 有类
  • 未找到 Gem 命令

    我已经在 Ubuntu 10 10 32 位上安装了 gem apt get install gem y 但当我尝试跑步时 gem install something gem 我收到未找到命令的错误 bash gem command not
  • 在 Docker 容器中以主机用户身份运行

    在我的团队中 我们在进行开发时使用 Docker 容器在本地运行我们的网站应用程序 假设我正在开发 Flask 应用程序app py具有依赖关系requirements txt 工作流程大致如下 I am robin and I am in
  • 无需 root 访问权限即可安装 zsh? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 有可能 以及如何 我确实需要在几台具有 ssh 访问权限 但没有 root 访问权限 的远程计算机上使用此功能 下载 zsh wget O zsh t
  • 如何重命名 .tar.gz 文件而不提取内容并在 UBUNTU 中创建新的 .tar.gz 文件?

    我有一个命令将创建一个新的 tar gz现有文件中的文件 sudo tar zcvf Existing tar gz New tar gz 该命令将创建一个新的New tar gz从现有的文件Existing tar gz file 谁能告
  • 如何列出 nginx 中的所有虚拟主机

    有没有一个命令可以列出 CentOS 上 nginx 下运行的所有虚拟主机或服务器 我想将结果通过管道传输到文本文件以用于报告目的 我正在寻找与我用于 Apache 的命令类似的命令 apachectl S 2 gt 1 grep 端口 8
  • 在非实时操作系统/内核上执行接近实时任务的最佳方法是什么?

    在一台 GNU Linux 机器上 如果想要执行 实时 亚毫秒级时间关键 任务 您几乎总是必须经历漫长 复杂且容易出现问题的内核补丁过程 以提供足够的支持 1 http en wikipedia org wiki RTLinux Backg
  • 提高mysql导入速度[关闭]

    Closed 这个问题是与编程或软件开发无关 help closed questions 目前不接受答案 我有一个很大的数据库22GB 我曾经用过进行备份mysqldumpgzip 格式的命令 当我提取 gz 文件时 它会生成 sql文件的
  • 如何将 elf 解释器(ld-linux.so.2/ld-2.17.so)构建为静态库?

    如果我的问题不准确 我深表歉意 因为我没有太多 Linux 相关经验 我目前正在构建一个 Linux 从头开始 主要遵循 linuxfromscratch org 版本的指南 7 3 我遇到了以下问题 当我构建可执行文件时 获取一个称为 E
  • 为什么默认情况下不启用 arp 忽略/通告 [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我有一个需要经验才能回答的具体问题 为什么 arp ignore arp announce 在 Linux 安装 例如 debian 上默认不启用 有
  • 比较linux中的两个未排序列表,列出第二个文件中的唯一项

    我有 2 个包含号码列表 电话号码 的文件 我正在寻找一种列出第二个文件中第一个文件中不存在的数字的方法 我尝试过各种方法 comm getting some weird sorting errors fgrep v x f second
  • 用于获取特定用户 ID 和进程数的 Bash 脚本

    我需要 bash 脚本来计算特定用户或所有用户的进程 我们可以输入 0 1 或更多参数 例如 myScript sh root deamon 应该像这样执行 root 92 deamon 8 2 users has total proces
  • 亚马逊 Linux - 安装 openjdk-debuginfo?

    我试图使用jstack在 ec2 实例上amazon linux 所以我安装了openjdk devel包裹 sudo yum install java 1 7 0 openjdk devel x86 64 但是 jstack 引发了异常j
  • 使用 --prof 选项创建多个日志文件而不是一个 v8.log 的节点

    我正在尝试使用 prof 选项来分析我的 Node 应用程序 但我发现不是一个单一的 v8 log 文件 而是使用诸如isolate 0x9582b40 v8 log isolate 0xa1cab78 v8 6049 等前缀创建的多个文件
  • 从哪里获取 iostream.h

    我正在尝试在 Linux 中做一些事情 但它抱怨找不到 iostream h 我需要安装什么才能获取此文件 这个标准头的正确名称是iostream没有扩展名 如果您的编译器仍然找不到它 请尝试以下操作 find usr include na
  • 由于 abi::cxx11 符号导致的链接问题?

    我们最近收到一份报告 因为GCC 5 1 libstdc 和双 ABI http gcc gnu org onlinedocs libstdc manual using dual abi html 它似乎Clang 不知道 GCC 内联名称
  • 如何从程序内部获取指向程序的特定可执行文件部分的指针? (也许是诽谤)

    我在 Linux 环境中 需要编写一个程序来检索放置在其可执行文件的某个部分中的一些数据 那么 如何从程序内部获取指向程序某个部分 通过其名称 的指针呢 我知道可以使用elf getdata 将节的索引作为参数传递给 get 和Elf Da
  • Unix 中的访问时间是多少

    我想知道访问时间是多少 我在网上搜索但得到了相同的定义 读 被改变 我知道与touch我们可以改变它 谁能用一个例子来解释一下它是如何改变的 有没有办法在unix中获取创建日期 时间 stat结构 The stat 2 结构跟踪所有文件日期

随机推荐

  • Nginx的405 not allowed错误解决

    1 问题情况 首先看到的页面是nginx返回的页面 得知错误要从nginx上来解决
  • 原生js中nextSibling和nextElementSibling的坑

    作者 拓海老师 公众号 拓海老师 一直以来js的随性让初学者蛋疼菊紧 但是真正玩熟了之后 还是非常有意思的 今天拓海老师跟大家说一下原生js中获取元素的下一个直接兄弟元素的坑 业务场景 点击当前元素 让其下一个紧挨着的兄弟元素展现出来 类似
  • 一文秒懂什么是DDoS攻击

    DDoS攻击是目前最常见的网络攻击方式之一 其见效快 成本低的特点 让DDoS这种攻击方式深受不法分子的喜爱 DDoS攻击经过十几年的发展 已经 进化 的越来越复杂 黑客不断升级新的攻击方式以便于绕过各种安全防御措施 一 什么是DDoS攻击
  • 使用Nginx作为一个普通代理服务器

    使用Nginx作为一个普通代理服务器 请不要用于违法用途哦 nginx作为一个反向代理工具 除了可以进行反向代理之外 还可以用来作为代理工具来使用 作为代理工具使用的步骤如下 这个配置目前支持对访问http协议的网站进行代理 暂不支持htt
  • linux7磁盘文件类型,CentOS 7 查看磁盘文件系统格式

    前提是磁盘已经格式化并挂载 可以直接查看 fstab 文件 cat etc fstab etc fstab Created by anaconda on Fri May 5 20 02 53 2017 Accessible filesyst
  • pycharm 每日提示

    打开每日提示 工具栏 help gt tip of the day 提示1 一个窗口打开多个项目 PyCharm can work with several projects in one window To open a project
  • PHPCMS标题设置

    phpcms v9的SEO首页和栏目页以及内容页都是可以独立配置 SEO代码在不同页面有不同意思以及不同的使用方法 优先级介绍 内容SEO gt 栏目SEO gt 站点SEO 首页 如果后台配置了站点SEO 则显示 SEO站点标题 否则显示
  • 经典GAN网络结构

    首先是Encoder部分 首先将通道数升至64 然后进行2次常规的尺寸减半 通道加倍 N 3 256 256 Conv 3 gt 64 7x7 s 1 rp 3 rp表示ReflectionPad2d IN ReLU N 64 256 25
  • Python3零基础7天入门实战,第8天没入门,来打锋哥。

    大家好 我是python222小锋老师 最近卷了一套Python3入门视频教程 文字版 视频版 7天轻松入门 视频版教程 Python3零基础7天入门实战视频教程 文字版目录 第一章 Python语言概述和开发环境 1 1 Python语言
  • 喇叭的灵敏度代表什么?规格型号是什么?

    常见型号 8 1W 8 2W 4 3w 单独从参数的角度上来说 灵敏度只是一个反映音箱电声转换效率的参数 其本身与音箱的音质与音色无关 扬声器的灵敏度 dB W 通常是指输入功率为1W的噪声电压时 在扬声器轴向正面1m处所测得的声压大小 灵
  • C ~ 循环

    有时 可能需要多次执行同一块代码 一般情况下 语句是顺序执行的 函数中的第一个语句先执行 接着是第二个语句 依此类推 编程语言提供了允许更为复杂的执行路径的多种控制结构 循环语句允许多次执行一个语句或语句组 大多数编程语言中循环语句的一般形
  • 文本预处理技巧:去除停用词、词形还原、词干提取等

    文本预处理是自然语言处理中非常重要的一步 它是为了使得文本数据能够被机器学习模型所处理而进行的一系列操作 其中 去除停用词 词形还原 词干提取等技巧是比较常用的 本文将介绍这些技巧的原理 并提供使用Python实现的代码示例 帮助读者更好地
  • 1.1.1.1校园网_突破校园网限制,开启寝室Wifi

    1 前言 由于学校的上网费用过于昂贵 所以和室友拼了一个学期的上网套餐 准备共享宽带账号并开启路由器 2 准备 一台刷好老毛子系统的路由器 一台正常上网的电脑 一根网线 工具 链接 https pan baidu com s 1mOFfFZ
  • 阻止事件的默认行为、React阻止事件的默认行为

    HTML中阻止事件的默认行为可以用return false a href Click me a 而React中只能显示调用e preventDefault function ActionLink function handleClick e
  • gitlab--基础--4.2--CICD--runner--常用命令

    gitlab 基础 4 2 CICD runner 常用命令 1 systemctl 读取的配置是 etc systemd system gitlab runner service文件 启动 systemctl start gitlab r
  • Linux下脚本实战之系统监控

    Linux下脚本实战之系统监控 一 脚本要求 二 脚本内容 三 运行脚本 一 脚本要求 1 监控系统的CPU 内存 硬盘使用率 二 脚本内容 bin bash File Name monitor sh Version V1 0 Aurhor
  • k8s Pod定义yaml配置文件详解

    此文件相关配置查询 此文件只做参考 以查询为准 kubectl explain 为文档查询命令如 kubectl explain pod spec volumes apiVersion v1 版本 kind pod 类型 pod metad
  • 互联网的行业都有哪些岗位?

    很多小伙伴想转行互联网 却对互联网行业知之甚少 今天小千就给大家简单介绍一下 方便感兴趣的同学自行入坑 互联网行业有哪些岗位 技术方向 架构师 前端工程师 后端工程师 人工智能 开发工程师 测试工程师 运维工程师等 市场方向 市场营销 媒介
  • Java之语言概述

    文章目录 1 软件开发介绍 1 1 常用的DOS命令 2 计算机编程语言介绍 3 Java语言概述 3 1 Java简史 3 2 Java技术体系平台 4 Java程序运行机制及运行过程 4 1 Java两种核心机制 2 垃圾收集机制 Ga
  • linux系统编程-2、进程

    前言 Linux系统编程的基础系列文章 随着不断学习会将一些知识点进行更新 前期主要是简单了解和学习 文章目录 进程 进程运行状态 进程原语 fork 进程相关函数 exec族 execl exec族区别 wait waitpid 进程 进