Linux系统编程:进程

目录

相关指令

ps指令

top指令       

相关函数及其示例

getpid()

 getpid()示例:

fork()

 示例:

示例2:fork()返回值

Father's pid is 14532.This is FartherProcess, pid is 14532.This is SonProcess, pid is 14533.

vfork()

 示例:与fork()区分

exit();_exit();_Exit();

abort()

wait()

示例:使用fork();wait();exit();

waitpid()

概念:孤儿进程

示例:getppid()可以获取父进程id

exec族函数

execl() 

示例:调用一个不存在的文件

示例:使用execl()调用ls指令

示例:获取系统时间 

execlp()

示例:execlp()调用ps指令

如何添加文件到环境变量呢?

execv()

system()

popen()

示例:使用popen()调用ls指令并获取其输出结果 


相关指令

ps指令

ps -aux        查看所有进程

ps -aux|grep init        筛选所有名字带init的进程

top指令       

类似win的任务管理器

相关函数及其示例

getpid()

获取当前线程的id

AMEgetpid, getppid - get process identificationSYNOPSIS#include <sys/types.h>#include <unistd.h>pid_t getpid(void);pid_t getppid(void);

 getpid()示例:

 #include <stdio.h>#include <sys/types.h>#include <unistd.h>int main(){pid_t pid;pid = getpid();printf("My pid is %d.\n",pid);return 0;}

输出:

My pid is 14142.

fork()

在调用出生成一个子进程。过去,创建子进程会直接复制一份父进程的内存空间,但后来经过改进,父子进程在存储空间上使用写时拷贝,即子进程对父进程的内存空间为只读,当需要操作某内存时,会将其拷贝。返回值0则为子进程,非负数父进程,调用失败-1。

NAMEfork - create a child processSYNOPSIS#include <sys/types.h>#include <unistd.h>pid_t fork(void);

 示例:

 #include <stdio.h>#include <sys/types.h>#include <unistd.h>int main(){pid_t pid;pid = getpid();fork();printf("My pid is %d.\n",pid);return 0;}

输出
My pid is 14258.
My pid is 14258.

pid在fork之前get,所以两次打印都是父进程pid

所以这样写

 #include <stdio.h>#include <sys/types.h>#include <unistd.h>int main(){pid_t pid;pid = getpid();fork();printf("Father's pid is %d.\n",pid);printf("My pid is %d.\n",getpid());return 0;}

输出:

Father's pid is 14289.
My pid is 14289.
Father's pid is 14289.
My pid is 14290.

示例2:fork()返回值

 #include <stdio.h>#include <sys/types.h>#include <unistd.h>int main(){pid_t pid,pFork;pid = getpid();printf("Father's pid is %d.\n",pid);pFork = fork();if(pFork > 0){printf("This is FartherProcess, pid is %d.\n",getpid());}else if(!pFork){printf("This is SonProcess, pid is %d.\n",getpid());}return 0;}

Father's pid is 14532.
This is FartherProcess, pid is 14532.
This is SonProcess, pid is 14533.
 

vfork()

vfork直接使用父进程内存空间,不拷贝。vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。

AMEvfork - create a child process and block parentSYNOPSIS#include <sys/types.h>#include <unistd.h>pid_t vfork(void);Feature    Test   Macro   Requirements   for   glibc   (see   fea‐ture_test_macros(7)):vfork():Since glibc 2.12:(_XOPEN_SOURCE >= 500) && ! (_POSIX_C_SOURCE >= 200809L)|| /* Since glibc 2.19: */ _DEFAULT_SOURCE|| /* Glibc versions <= 2.19: */ _BSD_SOURCEBefore glibc 2.12:_BSD_SOURCE || _XOPEN_SOURCE >= 500

 示例:与fork()区分

使用fork():

 #include <stdio.h>#include <sys/types.h>#include <unistd.h>int main(){pid_t pid,pFork;pid = getpid();printf("Father's pid is %d.\n",pid);pFork = fork();while(1){sleep(1);if(pFork > 0){printf("This is FartherProcess, pid is %d.\n",getpid());}else if(!pFork){printf("This is SonProcess, pid is %d.\n",getpid());}}return 0;}

输出:都可以运行 

查看进程 都为S+ ,都在运行

若改为使用vfork(),让子进程运行三秒退出:

 #include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <unistd.h>int main(){int cnt = 0;pid_t pid,pFork;pid = getpid();printf("Father's pid is %d.\n",pid);pFork = vfork();while(1){sleep(1);if(pFork > 0){printf("This is FartherProcess, pid is %d.\n",getpid());}else if(!pFork){printf("This is SonProcess, pid is %d.\n",getpid());cnt++;if(cnt == 3)  exit(0);}}return 0;}

运行:子进程运行了3次,子进程退出之前父进程阻塞,子进程退出之后,父进程才开始运行。

但是可以注意到一个现象,子进程退出后,子进程会变为Z+,即Zombie僵尸进程。

所以引出我们在进程编程中的一个问题,即 父进程等待子进程退出 并收集子进程退出状态 ,如果子进程退出状态不被收集,变成僵尸进程。

exit();_exit();_Exit();

NAMEexit - cause normal process terminationSYNOPSIS#include <stdlib.h>void exit(int status);
NAME_exit, _Exit - terminate the calling processSYNOPSIS#include <unistd.h>void _exit(int status);#include <stdlib.h>void _Exit(int status);Feature    Test   Macro   Requirements   for   glibc   (see   fea‐ture_test_macros(7)):_Exit():_ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L

abort()

NAMEabort - cause abnormal process terminationSYNOPSIS#include <stdlib.h>void abort(void);

wait()

NAMEwait, waitpid, waitid - wait for process to change stateSYNOPSIS#include <sys/types.h>#include <sys/wait.h>pid_t wait(int *wstatus);pid_t waitpid(pid_t pid, int *wstatus, int options);int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);/* This is the glibc and POSIX interface; seeNOTES for information on the raw system call. */

示例:使用fork();wait();exit();

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>int main(){int cnt = 0;pid_t pid,pFork;pid = getpid();printf("Father's pid is %d.\n",pid);pFork = fork();wait(NULL);while(1){sleep(1);if(pFork > 0){printf("This is FartherProcess, pid is %d.\n",getpid());}else if(!pFork){printf("This is SonProcess, pid is %d.\n",getpid());cnt++;if(cnt == 3)  exit(0);}}return 0;
}

现象:使用fork后正常应该父子进程都在运行,但是因为wait,所以父进程等待子进程退出。

(如果使用waitpid(),一个选项可以使父进程不阻塞) 

也不会产生僵尸进程


那么,status这个参数又是什么?

status为状态参数:子进程退出状态放在它所指向的地址中,空则为不关心其退出状态 

示例:让我们试着传递status,记得想读status,要用 WEXITSTATUS() 这个宏。

关于这个宏不多看,man 2 wait,就知道为什么了,可以顺带看看其它宏干嘛的

代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>int main(){int cnt = 0;int status = 0;pid_t pid,pFork;pid = getpid();printf("Father's pid is %d.\n",pid);pFork = fork();wait(&status);if(pFork > 0) printf("ChildProcess exit, exit_status : %d.\n",WEXITSTATUS(status));while(1){sleep(1);if(pFork > 0){printf("This is FartherProcess, pid is %d.\n",getpid());}else if(!pFork){printf("This is SonProcess, pid is %d.\n",getpid());cnt++;if(cnt == 3)  exit(3);}}return 0;
}

运行:读取到状态值为3

waitpid()

上面刚刚提到了使用waitpid(),一个选项可以使父进程不阻塞

同理man 2 wait,option怎么填,WNOHANG就是不阻塞,大家可以自行实验。

       The value of options is an OR of zero or more of the following constants:WNOHANGreturn immediately if no child has exited.WUNTRACEDalso return if a child has stopped (but not traced via ptrace(2)).  Status for traced children which have  stopped  isprovided even if this option is not specified.WCONTINUED (since Linux 2.6.10)also return if a stopped child has been resumed by delivery of SIGCONT.(For Linux-only options, see below.)

概念:孤儿进程

父进程在子进程退出之前就退出了,子进程会变为孤儿进程;Linux为避免系统存在过多孤儿进程,init进程将收留孤儿进程,变成其父进程。

示例:getppid()可以获取父进程id

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>int main(){int cnt = 0;int status = 0;pid_t pid,pFork;pid = getpid();printf("Father's pid is %d.\n",pid);pFork = fork();while(1){sleep(1);if(pFork > 0){cnt++;if(cnt == 3)  exit(0);}else if(!pFork){printf("SonProcess' pid is %d,my father's pid : %d.\n",getpid(),getppid());}}return 0;
}

现象:父进程退出后,子进程的父进程变成了1519 

kill ‘pid’        指令可以终止这个子进程 

exec族函数

Linux系统编程中很重要的一系列函数

linux进程---exec族函数(execl, execlp, execle, execv, execvp, execvpe)_分别用execlp()、execl()和execv()函数实现命令“find / -name abc-CSDN博客

 总结来说就是在调用进程内部执行一个文件

NAMEexecl, execlp, execle, execv, execvp, execvpe - execute a fileSYNOPSIS#include <unistd.h>extern char **environ;int execl(const char *pathname, const char *arg, .../* (char  *) NULL */);int execlp(const char *file, const char *arg, .../* (char  *) NULL */);int execle(const char *pathname, const char *arg, .../*, (char *) NULL, char *const envp[] */);int execv(const char *pathname, char *const argv[]);int execvp(const char *file, char *const argv[]);int execvpe(const char *file, char *const argv[],char *const envp[]);

execle和execvpe初学用的少,涉及到对环境变量的修改。

exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。

参数说明:
path:可执行文件的路径名字
arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。

exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:
l :   使用参数列表
p:使用文件名,并从PATH环境进行寻找可执行文件
v:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量

execl() 

需要文件路径,不知道可以使用 whereis XXX 指令来寻找 

示例:调用一个不存在的文件

使用了execl() 和 perror()

//文件execl.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);int main(void)
{printf("before execl\n");if(execl("/bin/echoarg","echoarg",NULL,NULL) == -1){printf("execl failed!\n");perror("why");}printf("after execl\n");return 0;
}

输出:

before execl
execl failed!
why: No such file or directory
after execl

示例:使用execl()调用ls指令

//文件execl.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);int main(void)
{printf("before execl\n");if(execl("/bin/ls","ls",NULL,NULL) == -1){printf("execl failed!\n");perror("why");}printf("after execl\n");return 0;
}

运行:成功调用ls,并且 after execl为被打印,因为调用之后进程被调用文件取代

示例:获取系统时间 

将ls换为date即可,可以看见执行了date指令

execlp()

可以直接在环境变量中寻找,不需要加路径。

示例:execlp()调用ps指令

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main(void)
{printf("before execlp\n");if(execlp("ps","ps","-l",NULL) == -1){printf("execl failed!\n");perror("why");}printf("after execlp\n");return 0;
}

如何添加文件到环境变量呢?

echo $PATH        查看环境变量

pwd        查看当前目录

export PATH=$PATH:你要添加到环境变量的目录

 可以看到添加了之后,我就可以用我自己实现的cp指令复制文件了(此实现详见我上一篇文章 文件编程)

execv()

区别在于使用数组指针传参

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main(void)
{char *argv[] = {"cp", "file", "file1",NULL};printf("before execv\n");if(execv("/bin/cp",argv) == -1){printf("execv failed!\n");perror("why");}printf("after execv\n");return 0;
}

system()

更加简单粗暴

system()函数的返回值如下: 成功,则返回进程的状态值; 当sh不能执行时,返回127; 失败返回-1;

NAMEsystem - execute a shell commandSYNOPSIS#include <stdlib.h>int system(const char *command);

示例:使用system()调用rm指令删除一个文件

#include <stdio.h>
#include <stdlib.h>int main(void)
{if(system("rm file1") == -1){printf("fail\n");}return 0;
}

popen()

比system()的优势:可以获取程序执行的结果

popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。

这个进程必须由 pclose() 函数关闭,而不是 fclose() 函数。pclose() 函数关闭标准 I/O 流,等待命令执行结束,然后返回 shell 的终止状态。如果 shell 不能被执行,则 pclose() 返回的终止状态与 shell 已执行 exit 一样。

也就是,popen创建管道,执行shell命令将文件流中的某些数据读出

NAMEpopen, pclose - pipe stream to or from a processSYNOPSIS#include <stdio.h>FILE *popen(const char *command, const char *type);int pclose(FILE *stream);

参数说明:

command: 是一个指向以 NULL 结束的 shell 命令字符串的指针。命令将被传到 bin/sh 并使用 -c 标志,shell 将执行这个命令,比如sh -c ls

type: 只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到 command 的标准输入。

返回值:
如果调用 fork() 或 pipe() 失败,或者不能分配内存将返回NULL,否则返回一个读或者打开文件的指针。

示例:使用popen()调用ls指令并获取其输出结果 

#include <stdio.h>
#include <unistd.h>int main(int argc ,char **argv){char ret[1024] = {0};FILE *fp;//FILE *popen(const char *command, const char *type);fp = popen("ls -l","r");//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);int nread = fread(ret,1,1024,fp);printf("read ret %d byte,\n%s\n",nread,ret);return 0;
}

运行结果 

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

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

相关文章

RabbitMQ下载与安装

一、Docker安装 1.单机部署 我们在Centos7虚拟机中使用Docker来安装。 1.1.下载镜像 方式一&#xff1a;在线拉取 docker pull rabbitmq:3-management方式二&#xff1a;从本地加载 上传到虚拟机中后&#xff0c;使用命令加载镜像即可&#xff1a; docker load -i mq.ta…

Docker上安装配置tomcat

目录 1. 拉取镜像 2. 创建运行镜像 3. 查看是否创建成功 ps&#xff1a;如果出现404错误 tomcat目录结构 1. 拉取镜像 这里使用 tomcat:8.5.40 版本作为安装 docker pull tomcat:8.5.40 2. 创建运行镜像 docker run -d --name tomcat -p 8080:8080 \--privilegedtrue …

改进的 K-Means 聚类方法介绍

引言 数据科学的一个中心假设是&#xff0c;紧密度表明相关性。彼此“接近”的数据点是相似的。如果将年龄、头发数量和体重绘制在空间中&#xff0c;很可能许多人会聚集在一起。这就是 k 均值聚类背后的直觉。 我们随机生成 K 个质心&#xff0c;每个簇一个&#xff0c;并将…

webstorm、vscode、HBuilder配置eslint检查

你们好&#xff0c;我是金金金。 场景 每个人写的代码都有自己所属的风格&#xff0c;所以项目中统一代码风格特别重要&#xff0c;新开的项目中如何快速配置ESLint呢&#xff1f; 安装 npm install --save-dev eslint ----安装eslintnpm install --save-dev eslint-plugin-vu…

事件分发机制:从OnTouchListener开始,按钮变色的Demo

要彻底弄清楚事件分发机制&#xff0c;先要明白OnTouchListener的作用。 我们看下Android 1.6上&#xff0c;OnTouchListener的代码定义&#xff0c;源码在线地址&#xff1a;Android 1.6 sdk4 View.java 可以看到&#xff0c;OnTouchListener就是View类中的一个public接口&am…

django+flask警务案件信息管理系统python-5dg53-vue

1&#xff09;用户在后台页面各种操作可及时得到反馈。 &#xff08;2&#xff09;该平台是提供给多个用户使用的平台&#xff0c;警员使用之前需要注册登录。登录验证后&#xff0c;警员才可进行各种操作[10]。 &#xff08;3&#xff09;管理员用户拥有信息新增&#xff0c;修…

Git 实战场景过程(工作总结篇)

目录 前言1. Git远程仓库建立分支&#xff0c;本地未显示1.1 问题所示1.2 知识补充 2. Git暂存内容切换分支2.1 问题所示2.2 知识补充 3. Git放弃修改数据3.1 问题所示3.2 知识补充 4. git merge合并查看差异 前言 主要总结工作中的疑惑点&#xff0c;如果你也有相应的场景&am…

跟着cherno手搓游戏引擎【19】抽象纹理

引入&#xff1a; 导入stb_image: GitHub - nothings/stb: stb single-file public domain libraries for C/C 下载复制stb_image.h的内容&#xff08;8000多行&#xff09;&#xff0c;然后粘到如图位置 stb_image.cpp: #include"ytpch.h" #define STB_IMAGE_IM…

【Java】MybatisPlus入门

学习目标 能够基于MyBatisPlus完成标准Dao开发 能够掌握MyBatisPlus的条件查询 能够掌握MyBatisPlus的字段映射与表名映射 能够掌握id生成策略控制 能够理解代码生成器的相关配置 一、MyBatisPlus简介 1. 入门案例 问题导入 MyBatisPlus环境搭建的步骤&#xff1f; 1.1 Sp…

部署实战--修改jar中的文件并重新打包成jar文件

一.jar文件 JAR 文件就是 Java Archive &#xff08; Java 档案文件&#xff09;&#xff0c;它是 Java 的一种文档格式JAR 文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中&#xff0c;多出了一个META-INF/MANIFEST.MF 文件META-INF/MANIFEST.MF 文件在生成 JAR 文件的时候…

DPVS 多活部署架构部署

一、目标 利用DPVS部署一个基于OSPF/ECMP的提供HTTP服务的多活高可用的测试环境。 本次部署仅用于验证功能&#xff0c;不提供性能验证。 配置两台DPVS组成集群、两台REAL SERVER提供实际HTTP服务。 注&#xff1a;在虚拟环境里面&#xff0c;通过在一台虚拟服务器上面安装FR…

flinkjar开发 自定义函数

编写自定义加密函数&#xff0c;继承ScalarFunction类&#xff0c;实现eval方法&#xff0c;参数个数类型和返回值根据业务来自定义。 import org.apache.flink.table.functions.ScalarFunction; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax…

ELK集群搭建(基础教程)

ELK集群搭建(基础教程) 目录&#xff1a; 机器准备 集群内各台机器安装Elasticsearch 安装部署Kafka&#xff08;注&#xff1a;每个节点都配置&#xff0c;注意ip不同&#xff09; 安装logstash工具 安装filebeat ELK收集Nginx的json日志 ELK收集Nginx正常日志和错误日…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之TimePicker组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之TimePicker组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 编辑 二、TimePicker组件 TextClock组件通过文本将当前系统时间显示在设备上。…

华为配置使用SNMPv1与网管通信示例

配置使用SNMPv1与网管通信示例 组网图形 图1 配置使用SNMPv1与网管通信组网图 SNMP简介配置注意事项组网需求配置思路操作步骤配置文件 SNMP简介 简单网络管理协议SNMP&#xff08;Simple Network Management Protocol&#xff09;是广泛应用于TCP/IP网络的网络管理标准协议。S…

AJAX-接口文档

接口文档&#xff1a;由后端提供的描述接口的文章 接口&#xff1a;使用AJAX和服务器通讯时&#xff0c;使用的URL&#xff0c;请求方法&#xff0c;以及参数 1.请求参数的位置为query&#xff08;查询&#xff09;的时候&#xff0c;就说明要使用params写为查询参数 2.请求参…

神经网络 | 基于多种神经网络模型的轴承故障检测

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本文主要源自《第二届全国技能大赛智能制造工程技术项目比赛试题&#xff08;样题&#xff09; 模块 E 工业大数据与人工智能应用》&#xff0c;基于给出的已知轴承状态的振动信号样本&#xff0c;对数据进行分析&#xff0c;建…

PDF中公式转word

效果&#xff1a;实现pdf中公式免编辑 step1: 截图CtrlAltA&#xff0c;复制 step2: SimpleTex - Snip & Get 网页或客户端均可&#xff0c;无次数限制&#xff0c;效果还不错。还支持手写、文字识别 单张图片&#xff1a;选 手写板 step3: 导出结果选择 注&#xff1a;…

pdmodel从动态模型转成静态onnx

1.下载项目 git clone https://github.com/jiangjiajun/PaddleUtils.git 2.新建两个新的文件夹 第一个文件夹放两个必要文件 第二个文件夹可以设置为空&#xff0c;用来存放转换后的模型 如图&#xff1a; 3.在终端运行 python paddle/paddle_infer_shape.py --model_dir …

谷粒商城【成神路】-【4】——分类维护

目录 1.删除功能的实现 2.新增功能的实现 3.修改功能的实现 4.拖拽功能 1.删除功能的实现 1.1逻辑删除 逻辑删除&#xff1a;不删除数据库中真实的数据&#xff0c;用指定字段&#xff0c;显示的表示是否删除 1.在application.yml中加入配置 mybatis-plus:global-config:…