Linux下的进程操作

进程概念

ps -elf:查看操作系统的所有进程(Linux命令)
ctrl + z:把进程切换到后台
crtl + c:结束进程
fg:把进程切换到前台

获取进程进程号和父进程号

函数原型:

pid_t getpid(void); //pid_t,它是一个有符号整数类型。
pid_t getppid(void);

例子:

#include <stdio.h>                                                                                                                                  
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t pid = getpid();printf("当前进程的进程号为:%d\n", pid);pid_t ppid = getppid();printf("当前进程的父进程为:%d\n", ppid);while(1);return 0;
}

fork

概念:fork() 是一个在操作系统编程中常用的函数,用于创建一个新的进程。它通过复制调用进程(称为父进程)来创建一个新的进程(称为子进程)。子进程是父进程的副本,它从 fork() 函数返回的地方开始执行。
在这里插入图片描述

以下是 fork() 函数的原型:

#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);

fork() 函数没有参数,它返回一个 pid_t 类型的值,表示进程的状态。返回值有以下几种情况:

  • 如果返回值是负数(-1),则表示创建子进程失败。
  • 如果返回值是零(0),则表示当前代码正在子进程中执行。
  • 如果返回值是正数,则表示当前代码正在父进程中执行,返回值是新创建子进程的PID。

例子:

#include <stdio.h>                                                                                                                                  
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main()
{       pid_t pid = fork();if(pid == -1){perror("fork");exit(1);}else if(pid == 0){       printf("child pid=%d, getpid=%d, getppid=%d\n", pid, getpid(), getppid());
//      while(1)
//      {printf("child\n");sleep(1);
//      }}else    {       printf("parent pid=%d, getpid=%d, getppid=%d\n", pid, getpid(), getppid());
//      while(1)
//      {printf("parent\n");sleep(2);
//      }}printf("helloworld\n");//会输出两次return 0;
}      

fork笔试题

详情看下述代码:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{for(int i = 0; i < 2; i++){   fork();//  printf("-\n"); //6个"-",换行符会输出缓冲区里的的数据printf("-"); // 8个"-",子进程会复制父进程输出缓冲区的数据}   return 0;
}

在这里插入图片描述
在这里插入图片描述

fork原理

在这里插入图片描述
下面输出都为1的原因是,父子进程在不同的空间

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{                                                                                                                                                   int num = 0;if(fork() == 0){   num++;printf("child %d\n", num);}   else{   num++;printf("parent %d\n", num);}/*输出为:child 1parent 1*/return 0;}

多进程读写

#include <stdio.h>                                                                                                                                  
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>void child_write(int fd)
{char buf[128] = {0};while(1){scanf("%s", buf);if(write(fd, buf, strlen(buf)) == -1){perror("write");break;}lseek(fd, -1 * strlen(buf), SEEK_CUR);if(!strcmp(buf, "bye"))break;memset(buf, 0, 128);}//i lseek(fd, -1 * strlen(buf), _CUR);}void parent_read(int fd)
{char buf[128] = {0};while(1){int ret = read(fd, buf, sizeof(buf));if(ret == -1){perror("read");break;}else if(ret == 0)continue;if(!strcmp(buf, "bye"))break;printf("child get: %s\n", buf);memset(buf, 0, sizeof(buf));}
}int main()
{int fd = open("hello.txt", O_CREAT | O_RDWR, 00400 | 00200);if(-1 == fd){perror("open");exit(1);}if(fork() == 0){child_write(fd);}else{parent_read(fd);}close(fd);return 0;
}          

vfork

vfork 是一个在某些操作系统中提供的系统调用函数,用于创建一个新的进程,并与父进程共享内存空间。与 fork 不同的是,vfork 在创建子进程时不会复制父进程的内存空间,而是与父进程共享同一份内存。这使得 vfork 函数比 fork 函数更高效,因为它不需要复制整个父进程的内存空间。

vfork 函数的语法如下:

#include <unistd.h>
pid_t vfork(void);

返回值:vfork 函数没有参数,返回一个进程ID(PID)。在父进程中,vfork 返回子进程的PID;在子进程中,vfork 返回0。如果 vfork 调用失败,返回-1。

注意事项:

  1. 子进程的执行:在调用 vfork 后,子进程会暂停父进程的执行,直到子进程调用 exec 函数族中的一个函数或者调用 _exit 函数来终止自己。子进程在执行期间与父进程共享同一份内存空间,因此需要谨慎处理共享资源的访问,以避免出现竞争条件和数据损坏等问题。
  2. 父进程的阻塞:在调用 vfork 后,父进程会阻塞,直到子进程调用 exec 函数族中的一个函数或者调用 _exit 函数,或者导致异常终止。
  3. 返回值的使用:根据 vfork 的返回值可以判断当前代码是在父进程还是子进程中执行。在父进程中,返回的是子进程的PID;在子进程中,返回的是0。可以根据这个返回值来区分父子进程的执行路径。
  4. vfork创建的子进程需要指定退出方式

例子:

#include <stdio.h>                                                                                                                                  
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main()
{pid_t pid = vfork();if(pid == -1){perror("vfork");exit(1);}else if(pid == 0) //子进程{printf("pid = %d, getpid = %d, getppid = %d\n", pid, getpid(), getppid());sleep(2);exit(0);}else //父进程{printf("pid = %d, getpid = %d, getppid = %d\n", pid, getpid(), getppid());}return 0;
}

exec系列函数

execl

execl 是一个系统调用函数,用于在当前进程中执行一个新的程序。它会取代当前进程的代码和数据,加载并执行指定的程序文件。
在这里插入图片描述

execl 函数的原型如下:

#include <unistd.h>
int execl(const char *path, const char *arg0, ..., (char *) NULL);

参数说明:
path:要执行的程序文件的路径。
arg0:新程序的第一个参数,通常是程序的名称。后续参数是新程序的命令行参数,以 NULL 结尾。
注意事项:当调用 execl 函数成功时,当前进程的代码和数据将被替换,之后的代码将不再执行。因此,如果在 execl 调用之后还有需要执行的代码,应该将其放在 execl 调用之前。

例子:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{if(vfork() == 0){   printf("child: pid=%d\n", getpid());//新的进程一旦启动,父进程就开始执行execl("/usr/bin/cp", "cp", "-r", "/usr/local", ".", NULL);printf("hello world!");//不会输出,因为执行了execl就不再执行下面的代码了}                                                                                                                                               else{printf("parent: pid=%d\n", getpid());}   return 0;
}   

拓展:
另外,execl 函数还有一些变种,如 execlp、execle、execv 等,它们在参数传递和执行方式上有所不同。可以根据具体的需求选择合适的函数来执行新程序。

孤儿进程 & 僵尸进程

孤儿进程:孤儿进程(Orphan Process)是指在父进程结束或被终止后,其子进程仍然在运行但失去了父进程的监管和控制。

孤儿进程的状态和行为有以下特点:

  1. 孤儿进程的父进程 ID(PPID)被设置为 init 进程的进程 ID(通常是 1)。
  2. 孤儿进程继续在系统中运行,但其父进程已经不存在。
  3. 孤儿进程的资源(如打开的文件描述符、内存等)不会被释放,因为它没有被正常地回收。
  4. 孤儿进程的终止状态(退出状态码)将被保存,直到父进程通过调用 wait 或 waitpid 等系统调用来获取。
  • 孤儿进程的存在是为了避免子进程在父进程终止后变成僵尸进程(Zombie Process)。当父进程没有及时处理子进程的终止状态时,子进程将变成僵尸进程,占用系统资源。而孤儿进程的终止状态会被保存,直到被新的父进程处理。

  • 在编写程序时,可以通过一些方式避免产生孤儿进程,例如在父进程终止之前等待子进程的终止,或者使用适当的进程管理和通信机制来确保子进程的正确终止和资源回收。

僵尸进程:僵尸进程(Zombie Process)是指一个已经终止执行的子进程,但其父进程尚未对其进行完全的资源回收和终止状态获取的进程。

僵尸进程的状态和行为有以下特点:

  1. 僵尸进程的状态(进程状态码)为 “Z” 或 “Z+”,在进程列表中以 “” 或 “Z” 标识。
  2. 僵尸进程的父进程仍然存在,但尚未调用相应的系统调用(如 wait 或 waitpid)来获取子进程的终止状态。
  3. 僵尸进程的资源(如打开的文件描述符、内存等)几乎没有消耗,因为它已经停止执行。
  4. 僵尸进程的终止状态(退出状态码)仍然保存在系统中,等待父进程来获取。
  • 僵尸进程的存在是因为在 Linux 系统中,子进程的终止状态需要被父进程显式地获取。父进程可以通过调用 wait、waitpid 或 waitid 等系统调用来获取子进程的终止状态,并进行相应的资源回收。如果父进程没有及时处理子进程的终止状态,子进程就会变成僵尸进程。
  • 僵尸进程一般不会对系统的正常运行产生直接影响,但如果大量的僵尸进程积累,可能会占用系统的进程表资源。因此,及时处理僵尸进程是良好的编程实践。

在编写程序时,可以通过以下方式避免僵尸进程的产生:

  1. 在父进程中使用 wait、waitpid 或 waitid 等系统调用来获取子进程的终止状态。
  2. 使用信号处理机制,在父进程中捕获子进程的终止信号(如 SIGCHLD),并在信号处理函数中处理子进程的终止状态。
  3. 使用进程间通信机制(如管道、信号量、共享内存等)来实现父进程与子进程之间的同步和通信,确保子进程的正确终止和资源回收。

例子:

#include <stdio.h>                                                                                                                                  
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>int main()
{if(fork() == 0){   sleep(1);printf("child: pid = %d, ppid = %d\n", getpid(), getppid());exit(100);}   else{   printf("parent: pid = %d\n", getpid());int status;wait(&status);if(WIFEXITED(status)) //判断子进程是否正常结束{   printf("子进程正常结束\n");printf("子进程退出状态:%d\n", WEXITSTATUS(status));}   else{printf("子进程异常退出\n");}}return 0;
} 

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

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

相关文章

Java服务端使用freemarker+wkhtmltoimage生成Echart图片

目录 1.通过 freemarker 将ftl转成html 1.1 freemarker 手册: 1.2 添加freemarker maven依赖 1.3 添加 echart-test.ftl 模版文件 1.4 添加 FreemarkerTool 工具类 1.5 添加测试main方法 1.6 运行,生成echart-test-时间戳.html 文件 2. 通过wkhtmltoimage将html 转为p…

Java项目实战--瑞吉外卖DAY03

目录 P22新增员工_编写全局异常处理器 P23新增员工_完善全局异常处理器并测试 p24新增员工_小结 P27员工分页查询_代码开发1 P28员工分页查询_代码开发2 P22新增员工_编写全局异常处理器 在COMMON新增全局异常捕获的类&#xff0c;其实就是代理我们这些controlle。通过aop把…

TikTok直播对网络环境的要求是怎么样的

TikTok直播作为一种互动性强、实时性要求高的社交媒体形式&#xff0c;对网络环境有着一系列特定的需求。了解并满足这些需求&#xff0c;对于确保用户体验、提高直播质量至关重要。本文将深入探讨TikTok直播对网络环境的要求以及如何优化网络设置以满足这些要求。 TikTok直播的…

docker环境搭建及其安装常用软件

centos安装docker Install Docker Engine on CentOS | Docker Docs 下载docker sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io…

x-cmd pkg | go - Google 开发的开源编程语言

目录 简介首次用户技术特点竞品分析编译型语言解释型语言JavaWebAssebmly 进一步阅读 简介 Go 语言&#xff08;或 Golang&#xff09;是 Google 开发的开源编程语言&#xff0c;诞生于 2006 年。其设计目标是“兼具 Python 等动态语言的开发速度和 C/C 等编译型语言的性能与安…

万字图解 | 深入揭秘HTTP工作原理

大家好&#xff0c;我是「云舒编程」&#xff0c;今天我们来聊聊计算机网络面试之-(应用层HTTP)工作原理。 文章首发于微信公众号&#xff1a;云舒编程 关注公众号获取&#xff1a; 1、大厂项目分享 2、各种技术原理分享 3、部门内推 前言 想必不少同学在面试过程中&#xff0…

JVM内存问题排查

本文又名《对JVM一窍不通的我快速开始排查应用内存问题》。主要系统性地整理了排查思路&#xff0c;为大家遇到问题时提供全面的排查流程&#xff0c;不至于漏掉某些可能性误入歧途浪费时间。 基本原则 由于本文的定位是Cookbook,基本原则是让整个流程能够系统化规范化的同时将…

【发展】不确定时代下的从容 —— 终局思维、长期主义与复利

文章目录 一、终局思维1、电影 《蝴蝶效应》2、未来是什么样的 二、长期主义1、这是一个不确定的时代2、做难但正确的事情 三、复利1、复利思维2、马太效应 一、终局思维 终局思维 在面对很多选择时&#xff0c;从终点出发考虑问题&#xff0c;来决定当下的选择。 1、电影 《蝴…

机电制造ERP软件有哪些品牌?哪家的机电制造ERP系统比较好

机电制造过程比较复杂&#xff0c;涵盖零配件、采购、图纸设计、工艺派工、生产计划、物料需求计划、委外加工等诸多环节。而供应链涉及供应商的选择、材料采购价格波动分析、材料交货、品质检验等过程&#xff0c;其中某个环节出现问题都可能会影响产品交期和经营效益。 近些…

编译和链接---C语言

引言 众所周知&#xff0c;C语言是一门高级的编程语言&#xff0c;是无法被计算机直接读懂的&#xff0c;C语言也不同于汇编PHP&#xff0c;无法直接翻译成机器语言&#xff0c;在学习的过程中&#xff0c;你是否好奇过我们所敲的C语言代码&#xff0c;是如何一步步翻译成机器…

k8s 容器 java 应用内存限制不生效

一 k8s java 应用内存限制不生效 回顾&#xff1a;Linux杂谈之java命令 容器环境JVM内存配置最佳实践 namespace负责资源隔离 cgroups负责资源限制 容器JVM最佳实践 Metaspace 是 非 Heap 内存 管理空间,那么 Heap 就是操作空间 JVM内存模型简介 隔离&#xff1a;…

web前端---------盒子模型

1.内容 盒子的内容可以包含文字、图片等多种类型。 浏览器在加载网页时&#xff0c;会将元素按照内容区分为替换元素与非替换元素。 &#xff08;1&#xff09;替换元素指的是HTML中的一些形如<img>、<input>等非文本元素。 这些元素本身不包含任何内容&#x…

vue3使用最新的属性defineModel实现父子组件数据响应式绑定

子父之间使用v-model双向绑定数据&#xff0c;子组件每次都要写emit和props觉得麻烦&#xff1f;以前&#xff0c;为了使组件支持与v-model双向绑定&#xff0c;它需要&#xff08;1&#xff09;声明prop&#xff0c;&#xff08;2&#xff09;在打算更新prop时发出相应的updat…

软件设计师——计算机网络(四)

&#x1f4d1;前言 本文主要是【计算机网络】——软件设计师——计算机网络的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1…

Oracle 19c rac集群管理 -------- 集群启停操作过程

Oracle rac集群启停操作过程 首先查看数据库的集群的db_unique_name SQL> show parameter nameNAME TYPE VALUE ------------------------------------ ----------- --------------------------- cdb_cluster_name …

Java Swing桌面项目打包成可执行jar

前言 最近有需求&#xff0c;将Swing项目打包为一个可执行的jar包&#xff0c;遇见了一些问题&#xff0c;参考AI助手&#xff0c;解决了遇到的问题&#xff0c;也有一些亲身实践体会&#xff0c;记录一下。开发环境IntelliJ IDEA&#xff0c;JDK8&#xff0c;用kotlin语言实现…

C#实现对任意区域任意大小的截图

1&#xff0c;目的: 实现类似系统截图工具那样对屏幕任何区域自定义大小的截图。 2&#xff0c;效果展示&#xff1a; 点击截图 选择需要截图的区域&#xff1a; 区域选择完成后&#xff0c;单击右键完成截图&#xff1a; 在合适的载体上粘贴截图&#xff1a; 3&#xff0c;…

Java基础进阶03-注解和单元测试

目录 一、注解 1.概述 2.作用 3.自定义注解 &#xff08;1&#xff09;格式 &#xff08;2&#xff09;使用 &#xff08;3&#xff09;练习 4.元注解 &#xff08;1&#xff09;概述 &#xff08;2&#xff09;常见元注解 &#xff08;3&#xff09;Target &#x…

C++:auto 关键字 范围for

目录 auto 关键字&#xff1a; 起源&#xff1a; auto的使用细则&#xff1a; auto不能推导的场景&#xff1a; 范围for&#xff1a; 范围for的使用条件&#xff1a; C的空指针&#xff1a; 注意&#xff1a; auto 关键字&#xff1a; 起源&#xff1a; 随着程序越…

【lodash.js】非常好用高性能的 JavaScript 实用工具库,防抖,深克隆,排序等

前言&#xff1a;lodash是一款前端必须要知道的js库&#xff0c;它里面提供了许多常用的功能和实用的工具函数 基本上我参与的项目中都有lodash&#xff0c;只能说lodash太强大了&#xff0c;lodash.js 提供了超过 300 个实用的工具函数&#xff0c;涵盖了很多常见的编程任务 l…