Linux进程控制(改)

news2024/11/25 2:46:05

Linux进程控制

进程 = 内核数据结构(struct task_struct,struct mm_struct,页表)+ 代码和数据

在Linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程

1.进程创建

  • ./程序
  • fork()创建子进程

2.fork函数

功能创建一个新的进程
头文件#include <unistd.h>
原型pid_t fork(void);
返回值成功: 0 或者大于 0 的正整数,失败:-1
备注该函数执行成功之后,将会产生一个新的子进程,在新的子进程中其返回值为0 ,在原来的父进程中其返回值为大于 0 的正整数,该正整数就是子进程的PID

fork可以用来创建一个子进程,一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值,而父进程中返回子进程ID

进程调用fork,当控制转移到内核中的fork代码后,内核做:

  1. 分配新的内存块和内核数据结构给子进程
  2. 将父进程部分数据结构内容拷贝至子进程
  3. 添加子进程到系统进程列表当中
  4. fork返回,开始调度器调度

fork调用失败的原因

  1. 系统中有太多的进程
  2. 实际用户的进程数超过了限制

3.进程终止(退出码和退出信号)

进程终止做的事:释放曾经代码和数据占据的空间,释放内核数据结构


进程正常终止时会返回进程的退出码(异常除外,无退出码):

  • 0:成功
  • !0:失败-------1.2.3.4.5.6….不同数字值代表不同失败原因对应相应的string错误信息

正常终止(可以通过 echo $? 查看进程退出码)

进程终止的3种情况

  1. 代码跑完,结果正确
  2. 代码跑完,结果错误
  3. 代码无法正确执行,出现异常(野指针…),这时候无法得到退出码,因此需要抛出异常

代码异常被操作系统终止本质是操作系统给进程抛出信号

例如: kill -l

在这里插入图片描述

如图所示退出信号

衡量一个进程退出,需要两个数字:退出码 + 退出信号!!


如何正常终止进程?

  1. 从main函数直接return返回
  2. 代码中调用void exit(int status)
  3. _exit:void _exit(int status);

exit()_exit()

前者会在进程退出时候冲刷缓冲区,后者不会

原因:前者是C库函数,后者是进行系统调用,而exit()实质上是调用_exit()这一个操作系统接口

如何异常终止进程?

  1. kill进程
  2. ctrl + c

任何子进程,在退出的情况下,一般必须被父进程进行等待

使进程退出的正确和错误方法:

  • 正确的方法
    • 在main函数中调用return:这会导致程序正常退出,并返回值给操作系统。
    • 在程序的任意位置调用exit接口exit函数会终止当前进程,并将控制权返回给操作系统。exit还会执行一些清理操作,比如调用注册的atexit函数,关闭所有标准I/O流等。
    • 在程序的任意位置调用_exit接口_exit_Exit函数会立即终止调用进程,但与exit不同,它不会执行任何清理操作,如关闭文件描述符,或刷新stdio缓冲区。
  • 错误的方法
    • 在程序的任意位置调用returnreturn语句只能用在函数内部来结束函数的执行,并返回一个值。如果在main函数中使用return,它会导致程序退出,但如果在其他函数中使用,它只会结束当前函数的执行,并不会导致进程退出。

4.进程等待的方法

wait

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

pid_t wait(int*status);
  • 参数:
    输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
  • 返回值:
    成功则返回被等待进程pid,失败:返回-1

waitpid

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

pid_ t waitpid(pid_t pid, int *status, int options);

waitpid函数参数的含义:

  • pid:要等待的进程的ID。特定值有特殊含义:

    • 如果pid-1waitpid会等待任何子进程
    • 如果pid大于0waitpid会等待进程ID与之相匹配的特定子进程
    • 如果pid等于0waitpid会等待与调用进程相同进程组的任何子进程
    • 如果pid小于-1waitpid会等待进程组ID等于pid绝对值的任何子进程
  • status:一个指向整数的指针,用于存储结束的子进程的状态信息。通过这个参数,调用者可以得知子进程是如何结束的(例如,是正常退出还是因为信号而结束)

    • WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出,查看退出信号)
    • WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
  • options:修改waitpid行为的选项。这些选项可以是以下几个值的组合:

    • WNOHANG即使没有子进程退出,它也会立即返回(非阻塞模式)
    • WUNTRACED:除了返回终止的子进程信息外,还返回因信号而停止的子进程信息
    • WCONTINUED:返回那些已经停止(因为job control信号)并且已经继续执行的子进程状态
  • waitpid函数的返回值是:

    • 如果成功,返回收集到状态信息的子进程的PID
    • 如果设置了WNOHANG且没有子进程退出,返回0
    • 如果出错,返回-1,并且errno会被设置为相应的错误代码

获取子进程status

  • wait,waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充
  • 如果传递NULL,表示不关心子进程的退出状态信息。否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程
  • status不能简单的当作整形来看待,可以当作位图来看待

进程等待实列:

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

int main()
{
    pid_t id = fork();
    if (id < 0)
    {
        perror("fork fail");
        exit(-1);
    }
    // child run
    if (id == 0)
    {
        printf("i am child process,pid = %d\n", getpid());
        sleep(5);
        // 子进程调用exit(0)来退出,并传递退出状态码0
        exit(0);
    }
    // father run and write the child status
    int status = 0;
    //使用wait方法
    pid_t ret = wait(&status);
    if (ret == -1)
    {
        perror("wait child fail");
        exit(-1);
    }
    // 如果进程正常退出,提取进程的退出码
    if (WIFEXITED(status))
    {
        // WEXITSTATUS(status)提取进程退出码
        // 当进程不是正常退出时候用WEXITSTATUS(status)是一种不可靠的行为
        printf("wait child exit success,exit_code:%d\n", WEXITSTATUS(status));
    }
    else
    {
        printf("wait child exit fail\n");
    }
    return 0;
}

进程非阻塞等待

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

int main()
{
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork fail");
        exit(0);
    }
    else if (pid == 0)
    { 
        // child
        int cnt = 5;
        while (cnt--)
        {
            printf("child is run, pid:%d,ppid:%d\n", getpid(), getppid());
            sleep(1);
        }
        exit(0);
    }
    else
    {
        // father
        int status = 0;
        pid_t ret = 0;
        do
        {
            ret = waitpid(-1, &status, WNOHANG); // 非阻塞式等待
            if (ret == 0)
            {
                // 子进程还没结束
                printf("Do father things\n");
            }
            sleep(1);
        } while (ret == 0);
        // 
        if (WIFEXITED(status) && ret == pid)
        {
            printf("wait child success, child exit code:%d\n", WEXITSTATUS(status));
        }
        else
        {
            printf("wait child failed\n");
            return 1;
        }
    }
    return 0;
}

进程阻塞等待

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

int main()
{
    pid_t pid = fork();

    if (pid < 0)
    {
        printf("%s fork error\n", __FUNCTION__);
        return 1;
    }
    else if (pid == 0)
    { 
        // child
        printf("child is run, pid is: %d\n", getpid());
        int cnt = 5;
        while (cnt)
        {
            printf("child[%d] is running, cnt = %d\n", getpid(), cnt);
            cnt--;
            sleep(1);
        }
        exit(1);
    }
    else
    {
        //father
        int status = 0;
        pid_t ret = waitpid(-1, &status, 0); // 阻塞式等待
        printf("wait child\n");
        if (WIFEXITED(status) && ret == pid)
        {
            printf("wait child success, child exit code:%d\n", WEXITSTATUS(status));
        }
        else
        {
            printf("wait child failed,\n");
            return 1;
        }
    }

    return 0;
}

5.进程程序替换

替换原理:

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec函数并不创建新进程,所以调用前后该进程的pid并未改变

总结:老进程的壳子执行新程序的代码


替换函数:

其实有六种以exec开头的函数,统称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[]);

实质上前五种函数是系统调用接口execve的封装


函数解释

  1. 这些函数如果调用成功则加载新的程序新的代码开始执行,不再返回到原代码中
  2. 如果调用出错则返回-1
  3. 所以exec函数只有出错的返回值而没有成功的返回值

命名理解

  1. l(list) : 表示参数采用列表
  2. v(vector) : 参数用数组
  3. p(path) : 有p自动搜索环境变量PATH
  4. e(env) : 表示自己维护环境变量

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

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

相关文章

GPS坐标转换为百度地图坐标并显示到百度地图上

百度地图有个坐标识取系统&#xff1a;https://api.map.baidu.com/lbsapi/getpoint/index.html&#xff0c;打开链接如下&#xff1a; 如上图&#xff0c;可以搜索某一个位置&#xff0c;然后会出现该位置的许多选择&#xff0c;选择一个就会显示出对应的百度地图的坐标&#x…

抖音小店正确的起店方法是什么?别再闭门造车了,快来学习!

大家好&#xff0c;我是电商糖果 随着抖音卖货的火爆的&#xff0c;开抖音小店的商家也越来越多。 很多没有电商经验的朋友就发现&#xff0c;想要起店非常难。 有的好一两个月了&#xff0c;都不出单。 糖果做抖音小店有四年时间了&#xff0c;也经营了多家小店。 这里就…

从零开始:如何进入IT行业

微信扫码体验我自己做的小程序&#xff08;很有意思哦&#xff5e;&#xff5e;【坏笑】&#xff09;&#xff1a; 随着科技的飞速发展&#xff0c;IT行业已经成为了许多人梦寐以求的职业之一。不过&#xff0c;对于那些没有任何相关经验或技能的人来说&#xff0c;进入这个领域…

坦克大战_java源码_swing界面_带毕业论文

一. 演示视频 坦克大战_java源码_swing界面_带毕业论文 二. 实现步骤 完整项目获取 https://githubs.xyz/y22.html 部分截图 启动类是 TankClinet.java&#xff0c;内置碰撞检测算法&#xff0c;线程&#xff0c;安全集合&#xff0c;一切皆对象思想等&#xff0c;是java进阶…

filetype: python中判断图像格式库imghdr替代库

引言 imghdr库是python中的一个内置库&#xff0c;用来判断图像原本格式的。自己一直有在用&#xff0c;不过近来看到这个库在python 3.13中会被移除。 自己感觉一直被python版本赶着走。这不找了好久&#xff0c;才找到一个替代库–filetype Python各个版本将要移除和可替代…

IoT数采平台4:测试

IoT数采平台1&#xff1a;开篇IoT数采平台2&#xff1a;文档IoT数采平台3&#xff1a;功能IoT数采平台4&#xff1a;测试 Modbus RTU串口测试 OPC测试 HTTP测试 MQTT透传测试 MQTT网关测试及数据上报 TCP / UDP 监听&#xff0c;客户端连上后发送信息&#xff0c;客户端上报数据…

C语言杂谈

努力扩大自己&#xff0c;以靠近&#xff0c;以触及自身以外的世界 文章目录 什么是定义&#xff1f;什么是声明&#xff1f;什么是赋值&#xff1f;什么是初始化&#xff1f;什么是生命周期&#xff1f;什么是作用域&#xff1f;全局变量&#xff1f;局部变量&#xff1f;size…

MySQL数据库(数据库连接池)

文章目录 1.批处理应用1.基本介绍2.批处理演示1.创建测试表2.修改url3.编写java代码 3.批处理源码分析 2.数据库连接池1.传统连接弊端分析2.数据库连接池基本介绍1.概念介绍2.数据库连接池示意图3.数据库连接池种类 3.C3P0连接池1.环境配置1.导入jar包2.将整个lib添加到项目中3…

云存储属性级用户撤销可追溯的密文策略属性加密方案论文阅读

参考文献为2018年发表的Traceable ciphertext-policy attribute-based encryption scheme with attribute level user revocation for cloud storage 贡献 本篇路提出了一个可追踪、实现属性级用户撤销&#xff08;删除用户的某一属性&#xff09;、支持密钥更新和密文更新、外…

图片二维码如何制作生成?常规图片格式的二维码制作技巧

图片是展示信息很常用的一种方式&#xff0c;而现在查看图片很多人会通过二维码的形式来展现&#xff0c;这种方式优势在于更加的灵活&#xff0c;能够通过一个二维码展示大量的图片内容。那么图片二维码是如何制作生成的呢&#xff1f; 想要快速的将图片转二维码使用&#xf…

mysql-FIND_IN_SET包含查询

如图所示&#xff0c;需要查询字段ancestorid中包含14的所有数据&#xff0c;使用FIND_IN_SET即可实现&#xff0c;不需要使用模糊查找like 示例sql&#xff1a; SELECT * FROM mt_fire_template WHERE FIND_IN_SET(14,ancestorid) 结果

【pysurvival Python 安装失败】

这个错误与 sklearn 包的名称更改有关&#xff0c;导致 pysurvival 在构建元数据时失败。现在&#xff0c;你需要修改 pysurvival 的安装文件以使用正确的 scikit-learn 包名 编辑安装文件&#xff1a;找到 pysurvival 的安装文件&#xff0c;可能是 setup.py 或 pyproject.to…

一文解析智慧城市,人工智能技术将成“智”理主要手段

长期以来&#xff0c;有关智慧城市的讨论主要围绕在技术进步方面&#xff0c;如自动化、人工智能、数据的公开以及将更多的传感器嵌入城市以使其更加智能化。实际上&#xff0c;智慧城市是一个关于未来的设想&#xff0c;其重要原因在于城市中存在各种基础设施、政治、地理、财…

华为OD面试手撕算法-合并排序数组

题目描述 本题是leetcode一道简单题&#xff1a;合并两个有序数组&#xff0c;但是对于时间和空间复杂度面试官明确给出了限制。 // 给定两个排序后的数组 A 和 B&#xff0c;其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法&#xff0c;将 B 合并入 A 并排序。 // 初始化…

【nc工具信息传输】

nc&#xff0c;全名叫 netcat&#xff0c;它可以用来完成很多的网络功能&#xff0c;譬如端口扫描、建立TCP/UDP连接&#xff0c;数据传输、网络调试等等&#xff0c;因此&#xff0c;它也常被称为网络工具的 瑞士军刀 。 nc [-46DdhklnrStUuvzC] [-i interval] [-p source_po…

“多组数组”题的注意事项,天杀的“鲁棒性”

【题目描述】 输入一些整数&#xff0c;求出它们的最小值、最大值和平均值&#xff08;保留3位小数&#xff09;。输入保证这些数都是不超过1000的整数。 输入包含多组数据&#xff0c;每组数据第一行是整数个数n&#xff0c;第二行是n个整数。n&#xff1d;0为输入结束标记&…

高分顶刊,仅2个月录用,13天见刊!另有CCF仅36天录用!

1区人工智能类SCIE &#xff08;高质量&#xff0c;进展顺&#xff09; 【期刊简介】IF&#xff1a;6.0-7.0&#xff0c;JCR1区&#xff0c;中科院2区 【检索情况】SCIE在检 【征稿领域】机器学习、云计算、边缘计算相关均可 【案例分享】2023.10.31 提交——2024.01.31 录…

ES6学习(四)-- Reflect / Promise / Generator 函数 / Class

文章目录 1. Reflect1.1 代替Object 的某些方法1.2 修改某些Object 方法返回结果1.3 命令式变为函数行为1.4 ! 配合Proxy 2. ! Promise2.1 回调地狱2.2 Promise 使用2.3 Promise 对象的状态2.4 解决回调地狱的方法2.5 Promise.all2.6 Promise.race 3. Generator 函数3.1 基本语…

计算机网络|谢希仁版|数据链路层

数据链路层 数据链路层研究的是什么&#xff1f;数据链路层的几个共同问题数据链路与链路帧通信规程 三个基本问题封装成帧透明传输差错检测可靠传输 点对点协议PPPPPP协议应满足的需求PPP协议的组成PPP协议帧的格式各字段的意义字节填充零比特填充PPP协议的工作状态 使用广播信…

How to install JDK on mac

文章目录 1. Install JDK on mac2. zshenv, zshrc, zprofile3. 查看java环境变量配置 1. Install JDK on mac Installation of the JDK on macOS 2. zshenv, zshrc, zprofile How Do Zsh Configuration Files Work? 3. 查看java环境变量配置 open Terminal&#xff0c;cd…