Linux 进程操作

文章目录

    • 进程的基本知识
      • 进程pid
      • 进程常用的函数
    • fork
    • wait和waitpid
    • exec函数簇
    • system函数
    • 信号处理signal函数
      • Linux的SIGUSR1SIGUSR2
    • 讨论

进程的基本知识

一个程序的执行称为一个进程,所有的代码都是在进程中执行的,进程是操作系统资源分配的基本单位。

在Linux中,除了内核的启动进程外,其他所有的进程都是由它的父进程通过fork函数调用产生的。

操作系统通过识别每一个进程的pid来识别每一个进程,pid在进程中是唯一的,可以重复利用(比如说前一个为pid=11的进程死掉了,那么pid=11的这个进程就可以分配给其他进程使用了:当pid达到最大限制时,内核会从头开始查找闲置的pid并使用最先找到的那一个作为新进程的id)
在这里插入图片描述

进程pid

操作系统中有一些进程的id是专用的:

  • id=0的进程为调度进程,调度进程是内核的一部分,并不执行任何磁盘上的程序
  • id=1的进程叫做 init 进程,init 进程是以超级用户权限运行着的普通用户进程,不是系统进程。

进程常用的函数

  • 头文件:#include<unistd.h>
  • __pid_t getpid (void):调用进程的进程ID
  • __pid_t getppid (void):调用进程的父进程ID
  • __uid_t getuid (void) :调用进程的实际用户ID
  • __uid_t geteuid (void):调用进程的有效用户ID
  • __gid_t getegid (void):调用进程的有效组ID

fork

  • fork用于进程的创建(完整的复制),使用fork()函数要引入头文件#include<unistd.h>,其函数原型为pid_t fork(void),fork返回值是pid_t,本质上是int类型。
  • 对于fork的返回值,如果是成功,子进程的id号会返回给父进程,并且把0返回给子进程;如果失败了,-1会返回给父进程,并且不会有子进程的创建,
//举一个简单的例子
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(){pid_t n=fork();if(n==0){//说明这是一个子进程printf("child:my pid=%d.,my ppid =%d\n",getpid(),getppid());}else if(n==-1){printf("程序创建错误\n");return -1;}else{sleep(1)//保证子进程可以执行完成printf("parent:my pid =%d,n=%d\n",getpid(),n);}
}
[cch@aubin s]$ gcc file.c
[cch@aubin s]$ ./a.out
child:my pid=3585.,my ppid =3584
parent:my pid =3584,n=3585
[cch@aubin s]$ 

以上的程序结果显示的是子进程先执行,而后父进程开始执行,但是实际上,在执行了fork之后,父进程与子进程都是同时存在的,也就是child:my pid=3585.,my ppid =3584语句和parent:my pid =3584,n=3585语句是同时执行的(并发执行),只是在执行父进程的时候进行了睡眠而已。

可能会出现以下的执行情况:

parent:my pid =3584,n=3585
[cch@aubin s]$ child:my pid=3585.,my ppid =3584

这是因为在并发执行的过程中,父进程先执行完毕,父进程执行完毕会返回给父进程的父进程,也就是系统调用,然后显示出来美元符号$,紧接着子进程也执行完毕,想要返回父进程会发现父进程已经结束了,只能返回上一层的上一层,也就是在美元符号后面显示。

wait和waitpid

  • 库函数exit(status)终止一进程,将进程占用的所有资源(内存、文件描述符等)归还内核。参数status为一整形变量,标识进程的退出状态。父进程可以通过系统调用wait()来获取该状态
  • 系统调用wait(&status)的目的有二:
    其一:如果子进程尚未调用exit()终止,那么wait()会挂起父进程直到有一个子进程终止
    其二:子进程的终止状态通过 wait()的 status 参数返回
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>int main(){pid_t pid;char *message;int n;int exit_code;pid=fork();switch(pid){case -1:exit( -1);case 0:message="child child";n=5;exit_code=37;break;default:message="father father";n=3;exit_code=38;break;}for(;n>0;n--){puts(message);sleep(1);}if(pid){//父进程int stat_val;pid_t child_pid;child_pid=wait(&stat_val);//父进程等待子进程的结束printf("child finish:pid=%d\n",child_pid);if(WIFEXITED(stat_val))//子进程正常终止的情况printf("child exit with code %d\n",WEXITSTATUS(stat_val));else//子进程非正常终止的情况printf("child terminated abnormally\n");}exit(exit_code);
}
[cch@aubin s]$ gcc file.c 
[cch@aubin s]$ ./a.out
father father
child child
father father
child child
father father
child child
child child
child child
child finish:pid=4459
child exit with code 37
[cch@aubin s]$ 
  • pid_t wait(int *status)用于等待子进程结束,回收并且释放子进程资源;其中status用来保存子进程退出时的状态,如果status为NULL,表示忽略子进程退出时的状态;如果函数执行成功,返回子进程的进程号,失败则返回-1。
  • pid_t waitpid(pid_t pid ,int *status , int options)waitpid相比于wait多了两个参数,options=0时,同wait,阻塞父进程,等待子进程退出。

op

exec函数簇

  • 用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用一个全新的程序替换了当前进程的正文、数据、堆和栈段。
  • exec本身不是一个函数,而是有6种不同的函数可供使用,所以被称为exec函数簇
#include <unistd.h>int execl( const char *pathname, const char *arg0, ... /* (char *)0 */ );int execv( const char *pathname, char *const argv[] );int execle( const char *pathname, const char *arg0, ... /* (char *)0, char *const envp[] */ );int execve( const char *pathname, char *const argv[], char *const envp[] );//进程映像的名字,映像所携带的参数,参数为0表示结束int execlp( const char *filename, const char *arg0, ... /* (char *)0 */ );int execvp( const char *filename, char *const argv[] );6个函数返回值:若出错则返回-1,若成功则不返回值
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>int main(){printf("exec:\n");execlp("ls","ls,0");printf("dome\n");exit(0);
}
[cch@aubin s]$ gcc file.c 
[cch@aubin s]$ ./a.out
exec:
dome
[cch@aubin s]$ 

system函数

  • int system(const char * command)system函数包含在头文件stdlib.h中,该函数会执行dos(windows系统) 或 shell(Linux/Unix系统) 命令,参数字符以command为命令名字。
  • 在windows系统中,system函数直接在控制台调用一个command命令。
    在Linux/Unix系统中,system函数会调用fork函数产生子进程,由子进程来执行command命令,并且使用wait阻塞父进程,直到子进程执行完毕后父进程继续执行
  • 命令执行成功返回0,执行失败返回-1。
#include<stdlib.h>
#include<stdio.h>int main(){printf("system:\n");system("ls");printf("dome\n");exit(0);
}
[cch@aubin s]$ gcc file.c 
[cch@aubin s]$ ./a.out
system:
a.out  file.c
dome
[cch@aubin s]$ 
system("ls &");//表示把子进程放到后台去做

信号处理signal函数

Linux中的信号可以通过kill -l命令获取

#include<signal.h>
#include<stdio.h>
#include<unistd.h>void ouch(int sig){printf("signal:%d\n",sig);(void)signal(SIGINT,SIG_DFL);//将ctrl+c的对应信号处理函数恢复成默认的值,也就是中断当前程序的执行
}int main(){(void)signal(SIGINT,ouch);//捕获信号ctrl+c,ouch是信号处理函数while(1){printf("hello world\n");sleep(1);}
}
  • void(* signal(int sig,void(* func)(int)))(int);指定使用sig指定的信号编号处理信号的方法。 其中void(* func)(int)表示的是一个带有int类型参数的函数指针;而signal本身的函数的返回值也是一个函数指针
  • 常用的sig包括(共32):
    • SIGINT:2,表示interrupt中断
    • SIGKILL:9,表示发送不可屏蔽的kill信号
    • SIGSEGV:11,表示segmentation violation,段违规
    • SIGUSR1:10,开放用户使用,默认处理进程终止
    • SIGUSR2:12,开放用户使用,默认处理进程终止
  • 参数func指定程序可以处理信号的三种方式之一:
    • 默认处理(SIG_DFL):信号由该特定信号的默认动作处理。
    • 忽略信号(SIG_IGN):忽略信号,即使没有意义,代码执行仍将继续。
    • 函数处理程序:定义一个特定的函数来处理信号。

除了在终端,也可以使用kil -2 pid来给对应的进程发送信号,表示系统向程序发送信号

Linux的SIGUSR1SIGUSR2

  • 当一个进程调用fork时,因为子进程在开始时复制父进程的存储映像,信号捕捉函数的地址在子进程中是有意义的,所以子进程继承父进程的信号处理方式。
  • 但是当子进程调用exec后,因为exec运行新的程序后会覆盖从父进程继承来的存储映像,那么信号捕捉函数在新程序中无意义,所以exec会将原本设置要捕捉的信号都更改为默认动作。

讨论

fotk语句执行成功后,会返回一个子进程的pid给父进程,并且返回0给子进程,由于父子进程并发执行,所以这个时候x的值为1或者-1都有可能,看父子进程谁先被调用。

尝试使用wait和waitid来同步父子进程的执行

child_pid=wait(&stat_val);//父进程等待子进程的结束
child_pid=wait(child_id,&stat_val,-1);//父进程等待子进程的结束

什么是execl函数簇

execl函数簇不是指一个函数,而是6个execl函数的统称,execl函数可以在不创建新进程的情况下,以一个全新的程序替换当前的程序的正文、数据和堆栈。

在一个程序中有多少种信号,怎么使用一个用户定义信号

#include<signal.h>
#include<stdio.h>
#include<unistd.h>
#include<signal.h>void signal_handle(int sig_num){if(sig_num==SIGUSR1)printf("SIGUSR1-----\n");//在命令行中发送SIGUSR1信号可以执行signal_handle函数printf("signal_handle\n");
}int main(){signal(SIGUSR1,signal_handle);while(1){printf("main------\n");sleep(1);}return 0;
}

在程序运行过程中,使用kill -s SIGUSR1 pid可以在命令行中发送对应的执行给程序,从而执行信号所对应的信号处理函数。

signal和sigaction的区别是什么

下面所指的signal都是指以前的older signal函数,现在大多系统都用sigaction重新实现了signal函数,不会出现空窗期。

  • signal在调用函数hander之前会有一段空窗期,在空窗期期间会先把hander指针恢复,这样会导致signal丢失信号,不能处理重复的信号;sigaction调用之后不会恢复hander指针,只有当再次调用sigaction修改handle指针才会恢复。

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

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

相关文章

JavaSE入门---认识类和对象

文章目录 什么是面向对象&#xff1f;认识类类的定义格式类的实例化 理解this引用对象的构造及初始化什么是构造方法&#xff1f;如何进行初始化&#xff1f;默认初始化就地初始化 认识staticstatic修饰成员变量static修饰成员方法 认识代码块普通代码块构造代码块静态代码块同…

代码随想录算法训练营第五十七天 | 392.判断子序列、115.不同的子序列

392.判断子序列 链接&#xff1a; 代码随想录 115.不同的子序列 链接&#xff1a; 代码随想录

零基础新手也能会的H5邀请函制作教程

随着科技的的发展&#xff0c;H5邀请函已经成为了各种活动、婚礼、会议等场合的常见邀约方式。它们不仅可以提供动态、互动的体验&#xff0c;还能让邀请内容更加丰富多彩。下面&#xff0c;我们将通过乔拓云平台&#xff0c;带领大家一步步完成H5邀请函的制作。 1. 选择可靠的…

Windows + Msys 下编译 TensorFlow 2.14

安装基本工具 宁滥毋缺 pacman -S --noconfirm --needed base-devel vim tar wget unzip protobufpacman -S --noconfirm --needed \${MINGW_PACKAGE_PREFIX}-cmake \${MINGW_PACKAGE_PREFIX}-gcc \${MINGW_PACKAGE_PREFIX}-toolchain \${MINGW_PACKAGE_PREFIX}-boost \${MING…

Go语言入门心法(十):Go语言操作MYSQL(CRUD)|事务处理

Go语言入门心法(一): 基础语法 Go语言入门心法(二): 结构体 Go语言入门心法(三): 接口 Go语言入门心法(四): 异常体系 Go语言入门心法(五): 函数 Go语言入门心法(六): HTTP面向客户端|服务端编程 Go语言入门心法(七): 并发与通道 Go语言入门心法(八): mysql驱动安装报错o…

设置hadoop+安装java环境

上一篇 http://t.csdnimg.cn/K3MFS 基本操作 接着上一篇 先导入之前导出的虚拟机 选择导出到对应的文件夹中 这里修改一下保存虚拟机的位置&#xff08;当然你默认也可以&#xff09; 改一个名字 新建一个share文件夹用来存放共享软件的文件夹 在虚拟机的设置中找到这个设置…

使用socket对http站点的访问

使用socket对http站点的访问 步骤&#xff1a; 1、实现TCP客户端 2、设置访问的网站地址 3、创建发送的请求报文 4、连接和发送报文到百度 5、显示百度回复的内容 import socket # 建立TCP连接 s socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 与服务器建立连接 host …

【Java 进阶篇】JavaScript BOM History 详解

当用户浏览网页时&#xff0c;可以使用JavaScript的BOM (Browser Object Model)中的History对象来访问浏览器的历史记录。这个对象允许您在不更改页面的情况下导航到不同的历史记录项&#xff0c;或者查看有关用户访问过的页面的信息。 在本篇博客中&#xff0c;我们将围绕Jav…

【软考-中级】系统集成项目管理工程师-合同管理历年案例

持续更新。。。。。。。。。。。。。。。 目录 2018 下 试题一(17分)系列文章 2018 下 试题一(17分) 阅读下列说明&#xff0c;回答问题 1至问题 3&#xff0c;将解答填入答题纸的对应栏内     某大型央企 A 公司计划开展云数据中心建设项目&#xff0c;并将公司主要业务应…

[BigData:Hadoop]:安装部署篇

文章目录 一&#xff1a;机器103设置密钥对免密登录二&#xff1a;机器102设置密钥对免密登录三&#xff1a;机器103安装Hadoop安装包3.1&#xff1a;wget拉取安装Hadoop包3.2&#xff1a;解压移到指定目录3.2.1&#xff1a;解压移动路径异常信息3.2.2&#xff1a;切换指定目录…

windows设置右键打开 vscode的方法(简易版)

实现效果如下&#xff1a; 如果安装VScode时没有选择下面两项&#xff0c;则无法通过快捷键打开 如何设置右键打开VSCode&#xff1f; 具体步骤如下&#xff1a; 找到 VSCode的快捷方式&#xff0c;右键选择 属性。 复制目标中的文件所在路径。 创建一个文本文档&#…

什么是低代码开发平台?有什么优势?

目录 一、低代码平台演进 1. 低代码概念 2. 低代码衍生历程 二、为什么要用低代码&#xff1f; &#xff08;1&#xff09;降本提效&#xff0c;便捷开发 &#xff08;2&#xff09;降低开发门槛&#xff0c;扩大应用开发劳动力 &#xff08;3&#xff09;加快数字化转型建设 三…

Leetcode—137.只出现一次的数字II【中等】

2023每日刷题&#xff08;二&#xff09; Leetcode—137.只出现一次的数字II 没有满足空间复杂度的Map题解 class Solution { public:int singleNumber(vector<int>& nums) {unordered_map<int, int>count;for(int iter: nums) {count[iter];}int ans 0;for(…

【Eclipse】查看版本号

1.在Eclipse的启动页面会出现版本号 2. Eclipse的关于里面 Help - About Eclipse IDE 如下图所示&#xff0c;就为其版本 3.通过查看readme_eclipse.html文件

Python合并同类别且相交的矩形框

Python合并同类别且相交的矩形框 前言前提条件相关介绍实验环境Python合并同类别且相交的矩形框代码实现 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩内容&#xff0c;可点击进入Python日常小操作专栏、YOLO系列专栏、自然语言处理专栏或…

YOLOv5算法改进(13)— 如何去更换主干网络(2)(包括代码+添加步骤+网络结构图)

前言:Hello大家好,我是小哥谈。为了给后面YOLOv5算法的进阶改进奠定基础,本篇文章就继续通过案例的方式给大家讲解如何在YOLOv5算法中更换主干网络,本篇文章的特色就是比较浅显易懂,附加了很多的网络结构图,通过结构图的形式向大家娓娓道来,希望大家学习之后能够有所收获…

记一次mysql事务并发优化

记一次mysql事务并发优化 背景 事情的情况大致是这样的。一个扣减库存的业务上线以后&#xff0c;隔几天会报一次错&#xff0c;错误内容如下&#xff1a; ERROR - exception: UncategorizedSQLException,"detail":"org.springframework.jdbc.UncategorizedSQ…

【Electron】Not allowed to load local resource

问题描述 使用 audio 标签播放音频文件&#xff0c;控制台报错 Not allowed to load local resource。 Not allowed to load local resource原因分析 通常是安全策略所引起的。Electron 默认情况下禁止加载本地资源&#xff0c;以防止潜在的安全风险。 解决方案 在 main.js…

协同创新、奔赴未来——“华为云杯”2023人工智能创新应用大赛华丽谢幕

9月27日&#xff0c;在苏州工业园区管理委员会、华为云计算技术有限公司的指导下&#xff0c;由SISPARK&#xff08;苏州国际科技园&#xff09;、华为&#xff08;苏州&#xff09;人工智能创新中心联合主办&#xff0c;东北大学工业智能与系统优化国家级前沿科学中心、浙江大…

批量xls转换为xlsx

import win32com.client as win32 import os# 另存为xlsx的文件路径 xlsx_file r"F:\志丹\1020Excel汇总\成果表备份\xlsx" xls_file r"F:\志丹\1020Excel汇总\成果表备份" for file in os.scandir(xls_file):suffix file.name.split(".")[-1…