Linux多进程开发-常用命令

news2024/12/30 3:06:19

进程

进程是计算机中正在运行的程序的实例。每个进程都有自己的地址空间、内存、文件和设备、线程以及其他系统资源。操作系统通过调度和管理进程来实现多任务处理,使得多个进程可以同时运行并与用户交互。在操作系统中,进程是基本的资源分配单位,它可以独立运行,也可以与其他进程进行通信和协作。

进程是程序的一次运行活动。

常用命令

在linux系统中,有几个常用的命令对进程进行操作。查看进程命令ps和top。结束进程命令kill,以及管道和重定向命令。

  1. 静态显示系统进程信息(ps)

    ps指令是linux系统标准的进程查看工具,通过它可以查看系统中进程的详细信息

    常用参数有:

    a:显示所有进程(包括其他用户的进程)
    u:以用户为主的格式来显示进程情况
    x:显示没有控制终端的进程
    e:显示环境变量
    f:做全格式列出
    l:长格式显示
    r:只显示正在运行的进程
    p:按照进程ID列出进程
    

    例子:

    ps            # 显示当前用户进程
    ps -aux       # 显示全部跟用户有关进程的所有信息
    

    常与管道组合使用:

    ps -aux |grep a    # 显示有关a进程的所有信息
    
  2. 动态显示系统进程信息(top)

    top命令相当于windows系统中的任务管理器,top是一个动态显示的过程,他通过不断的刷新当前的状态以动态的显示进程。调用top之后,它将独占前台,直到用户终止该程序(ctrl + c)。

    语法:

    top [-d] | top [-bnp]
    

    常用参数:

    -b:以批处理模式操作。
    -c:显示完整的命令行。
    -d:屏幕刷新间隔时间。
    -I:忽略失效过程。
    -s:保密模式。
    -S:累积模式。
    -i:不显示闲置和僵死进程。
    -n:更新显示次数。
    

进程标识符

每个进程都有一个非负整数表示唯一的ID,叫做pid,类似我们的身份证。

编程调用getpid函数获取本身的进程标识符,调用getppid获取父进程的进程标识符。

Linux进程控制

进程创建

在Linux系统中,创建进程的方式有两种:操作系统创建,和父进程创建。操作系统创建的进程是平等关系的,而父进程创建的子进程不是平等关系,而且相互之间存在资源继承的关系。而且父进程创建的子进程又可以创建子进程,从而形成一个进程家族。

fork函数

系统创建进程的通用方法是使用函数fork();我们通过在Linux终端输入man 2 fork命令,我们看到fork的使用说明。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=e0575ecf287cebd8c3d514274b6e31de
.png&pos_id=img-S99QMrCK-1733831801522)

该函数的返回类型为整形,若是父进程则放回值为一个正整数,是子进程的pid号。若为子进程,则返回值为0。我们可以写段代码进行试验。

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

int main()
{
    pid_t pid;
    printf("befor fork\n");
    printf("father process pid = %d \n",getpid());
    pid = fork();

    if(pid > 0)
    {
        printf("this is father;pid = %d\n",getpid());
    }
    else if(pid == 0)
    {
        printf("this is son; pid = %d\n",getpid());
    }
    return 0;
}

我们看到以下结果:在这里插入图片描述

如果你使用man命令,发现他找不到这些,出现以下情况:

在这里插入图片描述

不要慌,按照以下步骤操作一下。

# 1、更新一下资源
sudo apt-get update   
# 2、安装标准c相关的帮助文档
sudo apt-get install libc-dev
sudo apt-get install glibc-doc

vfork函数

man 2 vfork命令看到的结果

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

pid_t vfork(void);

我们看到与fork函数一个样子,该函数也是放回一个整形,也是创建一个新的进程,但是他们两个函数是不一样的。与fork函数作比较,虽然功能和参数都类似,但是也有自己的独特之处。例如:

  1. fork函数创建子进程是对父进程的完全拷贝,所谓完全拷贝就是将父进程的代码完全复制一份运行,这样子子进程就能完全独立于父进程运行,这样子的代码具有良好的并发性;而vfork函数创建的子进程,是和父进程共享地址空间,子进程需要完全运行在父进程的地址空间上,子进程对地址空间的数据修改同样会影响到父进程。
  2. vfork函数创建的子进程会优先运行,当它执行完exit或者exec后,父进程才可以运行;而fork函数创建的子进程运行的优先级取决于系统的调度算法。

由于vfork函数不会复制父进程的地址空间,会节省系统大量的开销,运行速度也非常快。

我们同样可以用几个代码来看看效果。

首先我们用fork函数来写一段代码

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

int main()
{
    pid_t pid;
    int cnt = 0;
    printf("befor fork\n");
    printf("father process pid = %d \n",getpid());
    pid = fork();

    if(pid > 0)
    {
        while(1){
            printf("this is father;pid = %d\n",getpid());
            sleep(2);
            printf("father: %d \n",cnt);
        }
    }
    else if(pid == 0)
    {
        while(1){
            cnt ++;
            printf("this is son; pid = %d\n",getpid());
            sleep(2);
            if(cnt >= 5)
            {
                printf("the son exit\n");
                exit(0);
            }
        }
    }
    return 0;
}

运行结果如下:

hyx@hyx-virtual-machine:~/c_project/c_Process$ ./a.out
befor fork
father process pid = 6759
this is father;pid = 6759
this is son; pid = 6760
father: 0
this is father;pid = 6759
this is son; pid = 6760
father: 0
this is father;pid = 6759
this is son; pid = 6760
father: 0
this is father;pid = 6759
this is son; pid = 6760
^C

通过运行结果我们看到,父进程和子进程在同时运行,并且在父进程中,子进程更改了值,但是父进程这边没有。

那这边用vfork修改一下代码

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

int main()
{
    pid_t pid;
    int cnt = 0;
    printf("befor fork\n");
    printf("father process pid = %d \n",getpid());
    pid = vfork();

    if(pid > 0)
    {
        while(1){
            printf("this is father;pid = %d\n",getpid());
            sleep(2);
            printf("father: %d \n",cnt);
        }
    }
    else if(pid == 0)
    {
        while(1){
            cnt ++;
            printf("this is son; pid = %d\n",getpid());
            sleep(2);
            if(cnt >= 3)
            {
                printf("the son exit\n");
                exit(0);
            }
        }
    }
    return 0;
}

运行结果:

befor fork
father process pid = 6975
this is son; pid = 6976
this is son; pid = 6976
this is son; pid = 6976
the son exit
this is father;pid = 6975
father: 3
this is father;pid = 6975
father: 3
this is father;pid = 6975
^C

通过结果我们发现,vfork函数创建的子进程会优先执行,在调用exit函数之后,父进程才开始运行,并且在子进程中对cnt的值进行了修改,在父进程中这个值也被修改了。


进程等待

在Linux系统中,当多个进程同时进行的时候,进程间需要协作工作,可能用到进程等待的操作。进程间的等待包括父子进程间的等待和进程组内成员间的等待。

同时用了wait方法接受推出的状态,如果子进程退出状态,没有被收集,子进程将变成僵尸进程。

进程等待有两种方法:wait和waitpid。
在Linux系统终端中使用帮助命令main wait,得到函数以下信息:

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

pid_t wait(int *wstatus);

pid_t waitpid(pid_t pid, int *wstatus, int options);

wait函数

wait函数返回类型为整形,wstatus为一个整形指针,用于存放子进程的结束状态。当wait被调用时,父进程处于挂起状态,只有当子进程结束返回。如果wait调用的父进程没有子进程,则返回失败。

调用成功:返回等待状态进程的pid; 调用失败:返回-1

我们同样用上面的代码的基础上,进行简单 的修改来看看情况。

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

int main()
{
	pid_t pid;
	int cnt = 0;
	int status;
	printf("befor fork\n");
	printf("father process pid = %d \n",getpid());
	pid = fork();

	if(pid > 0)
	{
		wait(&status);
		printf("status = %d\n",status);
		while(1){
			printf("this is father;pid = %d\n",getpid());
			sleep(2);
			printf("father: %d \n",cnt);
		}
	}
	else if(pid == 0)
	{
		while(1){
			cnt ++;
			printf("this is son; pid = %d\n",getpid());
			sleep(2);
			if(cnt >= 3)
			{
				printf("the son exit\n");
				exit(1);
			}
		}
	}
	return 0;
}

运行结果如下:

befor fork
father process pid = 7374 
this is son; pid = 7375
this is son; pid = 7375
this is son; pid = 7375
the son exit
status = 65280
this is father;pid = 7374
father: 0 
this is father;pid = 7374
^C

通过运行结果我们可以看到,用wait同样也可以使子线程优先运行。但是,接受到的status不是我们以为的值。那是因为,我们如果想要的是放回的值,那么我们还需要添加那些用于解释进程退出状态的宏。

我们将WEXITSTATU(status)代替status,我们就能得到正常的输出了。

在这里插入图片描述

waitpid函数

waitpid函数,返回值为整型,调用更加灵活,用于等待指定的进程。

status参数是个整形的指针用于存放子进程的结束状态。

pid参数是个整型参数,pid用于指定所等待的进程。

options参数指定所作的操作,取值0:表示进程挂起等待结束;取值WNOHANG表示不使进程挂起而即刻返回;取值WUNTRACED表示进程已经结束并返回。

调用成功返回等待状态的ID;调用失败返回-1。

我们魔改一下wait的代码,使用waitpid代替wait。代码如下:

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

int main()
{
	pid_t pid;
	int cnt = 0;
	int status;
	printf("befor fork\n");
	printf("father process pid = %d \n",getpid());
	pid = fork();

	if(pid > 0)
	{
		waitpid(pid,&status,0);
		printf("status = %d\n",WEXITSTATUS(status));
		while(1){
			printf("this is father;pid = %d\n",getpid());
			sleep(2);
			printf("father: %d \n",cnt);
		}
	}
	else if(pid == 0)
	{
		while(1){
			cnt ++;
			printf("this is son; pid = %d\n",getpid());
			sleep(2);
			if(cnt >= 3)
			{
				printf("the son exit\n");
				exit(37);
			}
		}
	}
	return 0;
}

运行结果:

befor fork
father process pid = 7530 
this is son; pid = 7531
this is son; pid = 7531
this is son; pid = 7531
the son exit
status = 37
this is father;pid = 7530
^C

通过运行结果,我们可以看到,用waitpid实现了wait函数同样的效果。


system函数

在linux环境下,我们使用man system看到system函数的信息如下:

#include <stdlib.h>

int system(const char *command);

我们可以在linux环境中使用system函数执行系统指令。command是一个字符串指针,指向表示命令的字符串。system函数可以执行系统命令,同时也可以调用fork、exec、waitpid。

接下来我们试一试:

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

int main()
{
	printf("show ls -a \n");
	system("ls -a");
	printf("done\n");
	exit(0);
	return 0;
}

结果如下:

show ls -a 
.  ..  01fork.c  02fork.c  03vfork.c  04wait.c	05waitpid.c  06system.c  a.out
done

结果与ls -a 效果相同。


总结

进程的相关操作是Linux编程的重要环节。熟悉这些进程控制的api的使用,对我们初学Linux平台下的c语言编程大有帮助。本文重点介绍了,进程的创建常用的俩函数,以及进程的等待。以及system函数。之后将重点介绍一下exec族。

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

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

相关文章

appium学习之二:adb命令

1、查看设备 adb devices 2、连接 adb connect IP:端口 3、安装 adb install xxx.apk 4、卸载 adb uninstall 【包名】 5、把对应目录下的1.txt文件传到手机sdcard下 adb push 1.txt /sdcard 6、进入对应的设备里 adb shell 7、切入sdcard目录 cd /sdcard 8、ls 查…

Redis篇-3--原理篇2--Redis事务

1、概述 Redis 提供了简单的事务机制&#xff0c;Redis 事务的本质是一组命令的集合。当执行redis事务时&#xff0c;即一次性按照添加顺序依次执行这些命令&#xff0c;中间不会被打断或者干扰。 Redis 的事务机制并不像关系型数据库中的事务那样提供完整的ACID特性&#xf…

简单网页制作提升用户体验和客户转化

在当今竞争激烈的市场中&#xff0c;用户体验和客户转化率往往是决定企业成败的关键。简单而高效的网页制作&#xff0c;正是提升用户体验和客户转化的重要手段之一。 首先&#xff0c;简洁的网页设计能够有效减轻用户的认知负担。当用户打开一个层次分明、界面整洁的网站时&am…

CDGA|数据治理:数据仓库”建设投入大、周期长怎么办?

在数据治理的广阔领域中&#xff0c;数据仓库的建设无疑是一项至关重要的任务。然而&#xff0c;这项任务往往伴随着巨大的投入和漫长的周期&#xff0c;成为许多企业面临的棘手问题。数据仓库作为数据存储、处理和分析的核心平台&#xff0c;其建设不仅需要大量的资金和技术支…

大中型水闸安全监测系统

一、背景 水闸作为水利工程中的重要组成部分&#xff0c;承担着调节水位、控制水流、防洪排涝等多重功能。然而&#xff0c;水闸在运行过程中会受到各种自然和人为因素的影响&#xff0c;导致其安全性能下降&#xff0c;甚至发生安全事故。为了保障水闸的安全运行&#xff0c;…

STL之空间配置器allocator

STL之空间配置器allocator 空间配置器的标准接口设计一个简单的空间配置器, JJ::allocator 具备次配置力(sub-allocation)的SGI空间配置器SGI标准的空间配置器, std::allocatorSGI特殊的空间配置器, std::alloc构造和析构基本工具:construct()和destroy()空间的配置与释放,std:…

人大金仓(KingBaseEs)数据库操作手册

人大金仓数据库&#xff08;KingbaseES&#xff09;是由北京人大金仓信息技术股份有限公司&#xff08;简称人大金仓&#xff09;自主研发的、具有自主知识产权的通用关系型数据库管理系统。 官方下载地址&#xff1a;KingbaseES 人大金仓数据库 KES技术文档在线手册&#xf…

容器镜像仓库

文章目录 1、docker hub1_注册2_登录3_创建容器镜像仓库4_在本地登录Docker Hub5_上传容器镜像6_下载容器镜像 2、harbor1_获取 docker compose 二进制文件2_获取harbor安装文件3_获取TLS文件4_修改配置文件5_执行预备脚本6_执行安装脚本7_验证运行情况8_访问harborUI界面9_har…

概率论相关知识随记

作为基础知识的补充&#xff0c;随学随记&#xff0c;方便以后查阅。 概率论相关知识随记 期望&#xff08;Expectation&#xff09;期望的定义离散型随机变量的期望示例&#xff1a;掷骰子的期望 连续型随机变量的期望示例&#xff1a;均匀分布的期望 期望的性质线性性质期望的…

如何解决压测过程中JMeter堆内存溢出问题

如何解决压测过程中JMeter堆内存溢出问题 背景一、为什么会堆内存溢出&#xff1f;二、解决堆内存溢出措施三、堆内存参数应该怎么调整&#xff1f;四、堆内存大小配置建议 背景 Windows环境下使用JMeter压测运行一段时间后&#xff0c;JMeter日志窗口报错“java.lang.OutOfMe…

快速了解 Aurora DSQL

上周在 AWS re:Invent大会&#xff08;类似于阿里云的云栖大会&#xff09;上推出了新的产品 Aurora DSQL[1] &#xff0c;在数据库层面提供了多区域、多点一致性写入的能力&#xff0c;兼容 PostgreSQL。并声称&#xff0c;在多语句跨区域的场景下&#xff0c;延迟只有Google …

java垃圾回收机制中的引用计数算法

垃圾回收机制 java 语言中一个显著的特点就是引入了java回收机制&#xff0c;是c程序Q员最头疼的内存管理的问题迎刃而解&#xff0c;它使得java程序员在编写程序的时候不在考虑内存管理。由于有个垃圾回收机制&#xff0c;iava中的额对象不在有“作用域”的概念&#xff0c;只…

android studio 读写文件操作(应用场景二)

android studio版本&#xff1a;2023.3.1 patch2 例程&#xff1a;readtextviewIDsaveandread 本例程是个过渡例程&#xff0c;如果单是实现下图的目的有更简单的方法&#xff0c;但这个方法是下一步工作的基础&#xff0c;所以一定要做。 例程功能&#xff1a;将两个textvi…

单片机C51--笔记8-STC89C51RC/RD-IIC协议

一、概述 IIC全称Inter-Integrated Circuit (集成电路总线) 是由PHILIPS公司在80年代开发的两线式串行总线&#xff0c;用于连接微控制器及其外围设备。IIC属于半双 工同步通信方式。 特点 简单性和有效性。 由于接口直接在组件之上&#xff0c;因此IIC总线占用的空间非常小…

小程序-基于java+SpringBoot+Vue的智慧校园管理系统设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

Linux下的编程

实验7 Linux下的编程 一、实验目的 熟练掌握Linux下Python编程的方法、函数调用方法以及shell编程中的控制结构。 二、实验环境 硬件&#xff1a;PC电脑一台&#xff0c;网络正常。 配置&#xff1a;win10系统&#xff0c;内存大于8G &#xff0c;硬盘500G及以上。 软件&a…

flink的安装配置(详细版本)

Standalone集群模式安装部署 conda deactivate 退出 base环境 Flink支持多种安装模式。 local&#xff08;本地&#xff09;——本地模式 standalone——独立模式&#xff0c;Flink自带集群&#xff0c;开发测试环境使用 standaloneHA—独立集群高可用模式&#xff0c;Fli…

【大语言模型】LangChain ModelsIO与Models I/O Promopts详解

【大语言模型】LangChain ModelsIO与Prompts详解 一、LangChain ModelsIO1、简介2、Models I/O 的应用场景3、Models I/O 主要模块3.1、Prompts3.2、Modelsa、MESSAGES 类型 3.3、Output Parsers 二、LangChain ModelsIO Prompts1、简介2、Prompts 的优点3、实战示例3.1、Promp…

Prometheus加入BasicAuth认证,通过配置 Prometheus 的 Web 身份验证来限制访问/debug/pprof/

Prometheus 作为监控工具&#xff0c;暴露了大量的系统监控数据和配置信息&#xff0c;这些数据可能包含敏感信息。Prometheus 默认没有身份验证&#xff0c;任何能够访问 Prometheus Web 界面的人都可以查看和查询这些数据。 此外Prometheus Web 界面的/debug/pprof/接口存在…

再谈多重签名与 MPC

目录 什么是 MPC 钱包以及它们是如何出现的 多重签名和智能合约钱包已经成熟 超越 MPC 钱包 关于小队 多重签名已经成为加密货币领域的一部分&#xff0c;但近年来&#xff0c;随着 MPC&#xff08;多方计算&#xff09;钱包的出现&#xff0c;多重签名似乎被掩盖了。MPC 钱包之…