进程控制 | 进程终止 | 进程等待 | 进程替换

文章目录

        • 1.进程终止
          • 1.1.理解C/C++中main函数的返回值
          • 1.2.进程终止的方式
        • 2.进程等待
          • 2.1.进程等待必要性
          • 2.2.进程等待系统调用
          • 2.3.获取子进程status
        • 3.进程替换
          • 3.1.进程程序替换引出
          • 3.2.如何进行进程的替换
          • 3.3.C/C++调用python

博客的完整代码连接: gitee

1.进程终止

Linux中进程创建会创建task_struct进程控制块、建立映射关系、加载"数据"(代码和数据)等一些列准备工作,反之进程终止操作系统会释放的对应的内核数据结构。简单的理解,创建进程是向操作系统申请资源,因为进程是系统资源分配的单位,而终止进程就是释放资源。

1.1.理解C/C++中main函数的返回值

在语言学习的阶段,main函数的固定结构都是返回值为0,为什么呢?非0行不行呢?

#incldue<stdio.h>int main()
{return 0;
}

返回值为0表示成功,非0表示运行结果不正确,非0有无数个可以标识不同的错误原因。而返回的意义是返回个上一级的父进程,用来判断这个程序的运行结构,当然如果不关心返回值这个return返回值可以忽略,甚至return也可以不写。

可以通过接口strerror查看系统定义的错误码对应的错误信息,当然错误码也是可以自定义的。

#include <stdio.h>
#include <string.h>int main()
{for(int number = 0;number < 150;number++){printf("the number is %d : strerrno %s\n",number,strerror(number));}return 0;
}

查看上一次进程的退出码:

echo $?
1.2.进程终止的方式

进程终止的场景: 代码运行完毕,结果正确、代码运行完毕,结果不正确、代码异常终止。

进程终止的方法:

正常终止:a.在main函数中,使用return返回;b.调用C语言体统的函数exit;c.系统调用_exit

异常终止:信号终止如:ctrl + c

exit和_exit的区别

其实exit()的底层是调用了_exit(),C语言对 _exit进一定的封装,如果我们使用printf打印函数,但是我们自己并没有主动的去刷新缓冲区,那么使用exit()函数来退出程序,会帮我们把缓冲区的数据刷新。

在这里插入图片描述

void test2()
{ 	// 注意不用\n行刷新printf("hello world");exit(0);
}void test3()
{// 注意不用\n行刷新printf("hello world");_exit(0);
}

分别调用,运行不同的程序,查看两个函数的输出。test2输出"hello world",test3不输出!

2.进程等待
2.1.进程等待必要性

原因:1.子进程比父进程先退出,父进程没有等待子进程,那么子进程会处于僵尸状态,如果子进程一直处于僵尸状态那么对应的内核数据结构得不到释放,就是占用内存造成,内存泄漏。其实,当父进程退出了,那么系统就会领养将子进程并将其释放(所以malloc没有free也是可以的,进程退出就释放了,但不要这么干)。但是,一般而言,我们创建的父进程长时间不会退出的,比如一个应用程序,是当用户点击退出的时候才会退出,在服务器端,一个服务器启动之后是不会退出的,要是发生内存泄漏就可以大事。 2.进程一旦变成僵尸状态,那就刀枪不入,"杀人不眨眼"的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程 3.父进程派给子进程的任务完成的如何,我们需要知道。如:子进程运行完成,结果对还是不对,或者是否正常退出

所以父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息,查看子进程完成父进程交给得任务得如何。

2.2.进程等待系统调用

wait系统调用:

pid_t wait(int *wstatus)

实验代码,创建子进程,父进程阻塞等待子进程

int WaitUse()
{pid_t pid = fork();if(pid < 0) {perror("fork process fail");return 1;}else if(pid == 0){for(int i = 0;i < 5;i++){printf("I am child pid = %d : ppid = %d\n",getpid(),getppid());sleep(1);}}else{pid_t wati_pid = wait(NULL); // 阻塞式等待printf("the wait no of return is %d\n",pid);printf("the father wait child success pid = %d : ppid = %d\n",getpid(),getppid());}return 0;
}

wait_pid系统调用:

pid_ t waitpid(pid_t pid, int *status, int options);
返回值:当正常返回的时候waitpid返回收集到的子进程的进程ID;如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:Pid=-1,等待任一个子进程。与wait等效。Pid>0.等待其进程ID与pid相等的子进程。
status:WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:可以设置阻塞和非阻塞式的等待,默认是0,阻塞式等待;设置WNOHANG是非阻塞。WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。

实验代码

int WaitPidUse()
{pid_t pid = fork();if (pid < 0){perror("fork process fail");return 1;}else if (pid == 0){for (int i = 0; i < 5; i++){printf("I am child pid = %d : ppid = %d\n", getpid(), getppid());sleep(1);}}else{int status = 0;pid_t ret = waitpid(pid, &status, 0);if (ret > 0){int status = 0;pid_t ret = waitpid(pid, &status, 0); // 阻塞式等待printf("this is test for wait\n");if (WIFEXITED(status) && ret == pid){printf("wait child  success, child return code is :%d.\n", WEXITSTATUS(status));}else{printf("wait child failed, return.\n");return 1;}}}return 0;
}
2.3.获取子进程status

当父进程阻塞式等待:wait和waitpid是等效的(waitpid(-1,&status,0) == wait(&status))

退出码和信号等信息都是通过status输出型变量来获取信息的,怎么获取?

在这里插入图片描述

3.进程替换
3.1.进程程序替换引出

当我们执行( . /可执行程序)的时候,系统会帮我们创建对应的内核结构和加载对应的可执行程序到内存当中。当我们fork创建子进程的时候并不会加载一份新的可执行程序到内存,而是公用一份父进程的代码。

如果我创建的子进程不想执行父进程中的一个代码片段,而是让我们创建的子进程去执行另外的进程,给怎么做?进程替换

在这里插入图片描述

3.2.如何进行进程的替换

替换函数其实有六种以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[]);

函数说明:这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值

命令理解记忆:

l(list) : 表示参数采用列表

v(vector) : 参数用数组

p(path) : 有p自动搜索环境变量PATH

e(env) : 表示自己维护环境变量

事实上,只有execve是真正的系统调用,其它五个函数最终都调用 execve,所以execve在man手册 第2节,其它函数在man手册第3节。

在这里插入图片描述

#include <stdio.h>
#include <iostream>
#include <unistd.h>using namespace std;int main(int argc,char* argv[],int env[]) // 注意对号入座
{//带不带(char*)没有问题,为了解除警告char *const _rgv[] = {(char*)"ps", "-ef", NULL};char *const _nvp[] = {"PATH=/bin:/usr/bin", "TERM=", NULL};execl("/bin/ps", "ps", "-ef", NULL);// 带p的,可以使用环境变量PATH,无需写全路径execlp("ps", "ps", "-ef", NULL);// int main(char* env[])//这样单独使用 execle函数接口给定环境变量是不行的!// 带e的,需要自己组装环境变量execle("ps", "ps", "-ef", NULL, _nvp);execv("/bin/ps", _rgv);// 带p的,可以使用环境变量PATH,无需写全路径execvp("ps", _rgv);// 带e的,需要自己组装环境变量execve("/bin/ps", _rgv, _nvp);//系统调用execvp("ls",_rgv);exit(0);
}
3.3.C/C++调用python

写一个python脚本模拟实现ll指令,chmod +x python文件,给python添加可执行权限,直接可以执行python脚本

import os
import sys
import stat
import pwd
import grp
import datetimedef get_file_permission(mode):permission = ''permission += 'd' if stat.S_ISDIR(mode) else '-'permission += 'r' if mode & stat.S_IRUSR else '-'permission += 'w' if mode & stat.S_IWUSR else '-'permission += 'x' if mode & stat.S_IXUSR else '-'permission += 'r' if mode & stat.S_IRGRP else '-'permission += 'w' if mode & stat.S_IWGRP else '-'permission += 'x' if mode & stat.S_IXGRP else '-'permission += 'r' if mode & stat.S_IROTH else '-'permission += 'w' if mode & stat.S_IWOTH else '-'permission += 'x' if mode & stat.S_IXOTH else '-'return permissiondef get_file_owner_and_group(uid, gid):try:owner = pwd.getpwuid(uid).pw_nameexcept KeyError:owner = str(uid)try:group = grp.getgrgid(gid).gr_nameexcept KeyError:group = str(gid)return owner, groupdef ll(path='.'):for filename in os.listdir(path):full_path = os.path.join(path, filename)stat_info = os.stat(full_path)mode = stat_info.st_modenlink = stat_info.st_nlinkuid = stat_info.st_uidgid = stat_info.st_gidsize = stat_info.st_sizeatime = datetime.datetime.fromtimestamp(stat_info.st_atime).strftime('%Y-%m-%d %H:%M:%S')mtime = datetime.datetime.fromtimestamp(stat_info.st_mtime).strftime('%Y-%m-%d %H:%M:%S')ctime = datetime.datetime.fromtimestamp(stat_info.st_ctime).strftime('%Y-%m-%d %H:%M:%S')permission = get_file_permission(mode)owner, group = get_file_owner_and_group(uid, gid)print(f'{permission} {nlink:2d} {owner:8s} {group:8s} {size:8d} {atime} {filename}')if __name__ == "__main__":if len(sys.argv) > 1:ll(sys.argv[1])else:ll()

程序替换代码:

int main() // 注意对号入座
{printf("进程替换调用之前!\n");execlp("python3"/*(解释器的位置)*/,"python","test.py",NULL);printf("进程替换调用之后!\n"); // 输出不了,程序替换了return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python系列】Python 解释器的站点配置

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

统信 UOS V20 一键安装 Oracle 19C(19.22)单机版

Oracle 一键安装脚本&#xff0c;演示 统信 UOS V20 一键安装 Oracle 19C&#xff08;19.22&#xff09;单机版过程&#xff08;全程无需人工干预&#xff09;&#xff1a;&#xff08;脚本包括 ORALCE PSU/OJVM 等补丁自动安装&#xff09; ⭐️ 脚本下载地址&#xff1a;She…

Django屏蔽Server响应头信息

一、背景 最近我们被安全部门的漏洞扫描工具扫出了一个服务端口的漏洞。这个服务本身是一个Django启动的web服务&#xff0c;并且除了登录页面&#xff0c;其它页面或者接口都需要进行登录授权才能进行访问。 漏洞扫描信息和提示修复信息如下: 自然这些漏洞如何修复&#xff0c…

【Docker】搭建安全可控的自定义通知推送服务 - Bark

【Docker】搭建安全可控的自定义通知推送服务 - Bark 前言 本教程基于绿联的NAS设备DX4600 Pro的docker功能进行搭建。 简介 Bark是一款为Apple设备用户设计的开源推送服务应用&#xff0c;它允许开发者、程序员以及一般用户将信息快速推送到他们自己的iPhone、iPad等设备上…

JY-7A/2DK/220静态电压继电器 200-420V 板前接线 josef约瑟

系列型号 JY-7A/1DK不带辅助电源电压继电器&#xff1b;JY-7B/1DK不带辅助电源电压继电器&#xff1b; JY-7/1DK/120不带辅助电源电压继电器&#xff1b;JY-7/1DK/120不带辅助电源电压继电器&#xff1b; JY-7A/1DKQ不带辅助电源电压继电器&#xff1b;JY-7B/1DKQ不带辅助电源…

如何测试360手机浏览器的 --360手机浏览器测试范围概述

一、基本测试 冒烟测试 由开发&#xff0c;测试&#xff0c;产品共同参与进行。 &#xff08;1&#xff09; 主流程和基本功能测试&#xff08;要求产品参与&#xff0c;如果不参与&#xff0c;一定要说明原因。测试确认此过程完成&#xff09; a) 将本次提测的核心功能过一…

uniapp 真机调试(mumu模拟器)

配置mumu模拟器 一、下载Mumu模拟器 https://mumu.163.com/ 二、点击安装&#xff0c;按步骤下一步安卓mumu模拟器 三、打开mumu多开器 右上角adb查看 端口号 四、打开mumu模拟器 五、打开HbuilderX 选择运行&#xff0c;运行到手机模拟器&#xff0c;Android模拟器端口设置…

【2024系统架构设计】案例分析- 4 嵌入式

目录 一 基础知识 二 真题 一 基础知识 1 基本概念 ◆系统可靠性是系统在规定的时间内及规定的环境条件下,完成规定功能的能力,也就是系统无故障运行的概率。或者,可靠性是软件系统在应用或系统错误面前,在意外或错误使用的情况下维持软件系统的功能特性的基本能力。

基于单片机汽车超声波防盗系统设计

**单片机设计介绍&#xff0c;基于单片机汽车超声波防盗系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机汽车超声波防盗系统设计概要主要涉及利用超声波传感器和单片机技术来实现汽车的安全防盗功能。以下是对…

ElementUI 周组件展示成月的第几周

ElementUI 周组件展示成月的第几周 组件展示 <el-date-picker unlink-panels :clearable"false" change"weekChange":editable"false" :type"dateType":value-format"valueFormat" :format"format"v-if&qu…

物联网监控可视化是什么?部署物联网监控可视化大屏有什么作用?

随着物联网技术的深入应用&#xff0c;物联网监控可视化成为了企业数字化转型的关键环节。物联网监控可视化大屏作为物联网监控平台的重要组成部分&#xff0c;能够实时展示物联网设备的运行状态和数据&#xff0c;为企业管理决策和运维监控提供了有力的支持。今天&#xff0c;…

对于最短路问题的一些总结

1、Dijkstra算法&#xff1a;每次用离源点最短的边去更新其他边&#xff0c;图中不能存在负权边&#xff0c;否则会破坏性质 **2、Bellman_Ford算法&#xff1a;非常暴力地去遍历所有地边&#xff0c;每次对边都进行更新&#xff0c;如果更新次数 > n - 1,则说明存在负权回…