Linux —— 进程控制

目录

一,进程创建

写时拷贝

二,进程终止

三,进程等待

获取子进程status


一,进程创建

  • 命令行启动命令(程序、指令等);
  • 通过程序自身fork创建;
#include<unistd.h>
//子进程返回0,父进程返回子进程的ID,出错返回-1
pid_t fork(void);

进程调用fork,当控制转移到内核中的fork代码后,内核将会:

  • 分配新的内存块和内核数据结构给子进程;
  • 拷贝父进程部分数据结构内容给子进程;
  • 添加子进程到系统进程列表中;
  • fork返回,开始调度器调度;

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

int main()
{
  pid_t pid;
  printf("Before: pid is %d\n", getpid());
  pid = fork();
  if(pid == -1)
  {
    perror("fork");
    exit(-1);
  }
  printf("After: pid is %d, fork return %d\n", getpid(), pid);
  sleep(1);
  return 0;                                                                 
}
[wz@192 Desktop]$ ./target 
Before: pid is 21739
After: pid is 21739, fork return 21740
After: pid is 21740, fork return 0
  • fork前,父进程独立执行;
  • fork后,父子进程分流执行;父子谁先执行完全由调度器决定;

写时拷贝

        通常父子代码共享,数据也共享(父子在不写入时);当有任意一方写入时,便以写实拷贝的方式各自一份副本,从而保证父子进程的独立性;

二,进程终止

  • 代码运行结束,结果正确,退出码为0;
  • 代码运行结束,结果不正确,退出码非0;
  • 代码异常终止;
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
  int i=0;
  for(i;i<200;i++)
  {
    printf("%d:%s\n",i,strerror(i));
  }
  return 0;                                                               
}
[wz@192 Desktop]$ ./target 
0:Success
1:Operation not permitted
2:No such file or directory
3:No such process
4:Interrupted system call
5:Input/output error
6:No such device or address
7:Argument list too long
8:Exec format error
9:Bad file descriptor
10:No child processes
11:Resource temporarily unavailable
12:Cannot allocate memory
13:Permission denied
14:Bad address
15:Block device required
16:Device or resource busy
17:File exists
18:Invalid cross-device link
19:No such device
20:Not a directory
21:Is a directory
22:Invalid argument
23:Too many open files in system
24:Too many open files
25:Inappropriate ioctl for device
26:Text file busy
27:File too large
28:No space left on device
29:Illegal seek
30:Read-only file system
31:Too many links
32:Broken pipe
33:Numerical argument out of domain
34:Numerical result out of range
35:Resource deadlock avoided
36:File name too long
37:No locks available
38:Function not implemented
39:Directory not empty
40:Too many levels of symbolic links
41:Unknown error 41
42:No message of desired type
43:Identifier removed
44:Channel number out of range
45:Level 2 not synchronized
46:Level 3 halted
47:Level 3 reset
48:Link number out of range
49:Protocol driver not attached
50:No CSI structure available
51:Level 2 halted
52:Invalid exchange
53:Invalid request descriptor
54:Exchange full
55:No anode
56:Invalid request code
57:Invalid slot
58:Unknown error 58
59:Bad font file format
60:Device not a stream
61:No data available
62:Timer expired
63:Out of streams resources
64:Machine is not on the network
65:Package not installed
66:Object is remote
67:Link has been severed
68:Advertise error
69:Srmount error
70:Communication error on send
71:Protocol error
72:Multihop attempted
73:RFS specific error
74:Bad message
75:Value too large for defined data type
76:Name not unique on network
77:File descriptor in bad state
78:Remote address changed
79:Can not access a needed shared library
80:Accessing a corrupted shared library
81:.lib section in a.out corrupted
82:Attempting to link in too many shared libraries
83:Cannot exec a shared library directly
84:Invalid or incomplete multibyte or wide character
85:Interrupted system call should be restarted
86:Streams pipe error
87:Too many users
88:Socket operation on non-socket
89:Destination address required
90:Message too long
91:Protocol wrong type for socket
92:Protocol not available
93:Protocol not supported
94:Socket type not supported
95:Operation not supported
96:Protocol family not supported
97:Address family not supported by protocol
98:Address already in use
99:Cannot assign requested address
100:Network is down
101:Network is unreachable
102:Network dropped connection on reset
103:Software caused connection abort
104:Connection reset by peer
105:No buffer space available
106:Transport endpoint is already connected
107:Transport endpoint is not connected
108:Cannot send after transport endpoint shutdown
109:Too many references: cannot splice
110:Connection timed out
111:Connection refused
112:Host is down
113:No route to host
114:Operation already in progress
115:Operation now in progress
116:Stale file handle
117:Structure needs cleaning
118:Not a XENIX named type file
119:No XENIX semaphores available
120:Is a named type file
121:Remote I/O error
122:Disk quota exceeded
123:No medium found
124:Wrong medium type
125:Operation canceled
126:Required key not available
127:Key has expired
128:Key has been revoked
129:Key was rejected by service
130:Owner died
131:State not recoverable
132:Operation not possible due to RF-kill
133:Memory page has hardware error
134:Unknown error 134
135:Unknown error 135
136:Unknown error 136
137:Unknown error 137
138:Unknown error 138

进程常见退出方法:

  • 正常终止,可通过 echo $? 查看最近一次执行程序退出码;
    • main返回,return 0代表进程退出,0退出码表示成功;给系统查看,以确认进程是否正确;非main函数的return不受终止进程,是结束函数;
    • exit,任意位置调用此函数,都会直接终止进程;
    • _exit,与exit类型,但此函数不会刷新缓冲区等处理工作,直接终止进程;
  • 异常退出;
    • ctrl + C,信号终止;

退出码可自定义,也可使用系统错误码;

#include <unistd.h>
void exit(int status);
#include <unistd.h>
void _exit(int status);
//status 定义了进程终止状态,父进程通过wait来获取该值;
//虽然status为int,但仅低8位可被父进程使用,_exit(-1)执行echo $?结果为255;

#include <stdio.h>
#include <stdlib.h>
int main()
{
  printf("hello");
  exit(0);                                                                  
  return 0;
}
[wz@192 Desktop]$ ./target 
hello[wz@192 Desktop]$ 
#include <stdio.h>
#include <stdlib.h>
int main()
{
  printf("hello");
  _exit(0);                                                                  
  return 0;
}
[wz@192 Desktop]$ ./target 
[wz@192 Desktop]$ 

return退出

        一种常见的退出进程方法,执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返回值当作exit的参数;

进程终止的核心思想,就是归还资源;

  • 释放曾经为管理进程所维护的所有数据结构对象;
    • 不是真的把数据结构对象销毁,而是设置为不用状态,保存起来,“数据结构池”;
  • 释放程序代码和数据所占的内存空间;
    • 不是将代码和数据清空,把内存设置为无效即可;
  • 取消曾经该进程的链接关系;

三,进程等待

进程等待的必要性

  • 子进程退出,父进程如不管不顾,就可能造成僵死进程,进而造成内存泄露;
  • 进程进入僵死状态,将无能为力,即使是kill -9,因为无法杀死一个已经死亡的进程;
  • 父进程交派给子进程的任务完成状况需知道,如子进程运行完,其结果对错与否,是否正常退出;
  • 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息;
  • 尽量父进程要晚于子进程退出,可规格化进行资源回收;

pid_t wait(int*status)

  • 返回值,成功,返回被等待进程pid;失败,返回-1;
  • 参数,获取子进程退出状态,不关心可设置为NULL;
#include<sys/types.h>
#include<sys/wait.h>

pid_t wait(int *status);
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    int i=0;
    //创建5个子进程,睡眠2秒退出 
    for(i=0; i<5; i++)
    {
        pid_t id = fork();
        if(id<0)
        {                                                                          
            perror("fork");
            return 1;
        }
        else if(id==0)
        {
            sleep(2);
            printf("child:pid=%d, ppid=%d, id=%d\n",getpid(),getppid(),id);
            exit(1);
        }
    }
    //父进程等待
    for(i=0; i<5; i++)
    {
        sleep(3);
        pid_t wait_pid = wait(NULL);
        printf("father:pid=%d, wait_pid=%d\n",getpid(), wait_pid);
    }
    sleep(3);
    printf("father finish!\n");
    return 0;
}
[wz@192 Desktop]$ ./target 
child:pid=116610, ppid=116606, id=0
child:pid=116607, ppid=116606, id=0
child:pid=116608, ppid=116606, id=0
child:pid=116609, ppid=116606, id=0
child:pid=116611, ppid=116606, id=0
father:pid=116606, wait_pid=116607
father:pid=116606, wait_pid=116608
father:pid=116606, wait_pid=116609
father:pid=116606, wait_pid=116610
father:pid=116606, wait_pid=116611
father finish!

pid_ t waitpid(pid_t pid, int *status, int options)

  • 返回值
    • 正常返回的时候,waitpid返回收集到的子进程的进程PID;
    • 如设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,返回0;
    • 如调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
  • 参数
    • pid
      • -1等待任一个子进程,与wait等效;
      • >0等待指定pid子进程;
    • status
      • WIFEXITED(status),若为正常终止子进程进程返回的状态,则为真;
      • WEXITSTATUS(status),若WIFEXITED非零,提取子进程退出码;
    • options
      • WNOHANG,若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待;
#include<sys/types.h>
#include<sys/wait.h>

pid_ t waitpid(pid_t pid, int *status, int options);
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    //创建子进程,睡眠2秒退出 
    pid_t id = fork();
    if(id<0)
    {                                                                          
        perror("fork");
        return 1;
    }
    else if(id==0)
    {
        sleep(2);
        printf("child:pid=%d, ppid=%d, id=%d\n",getpid(),getppid(),id);
        exit(1);
    }
    //父进程等待
    sleep(5);
    pid_t wait_pid = waitpid(id, NULL, 0);
    printf("father:pid=%d, wait_pid=%d\n",getpid(), wait_pid);
    sleep(3);
    printf("father finish!\n");
    return 0;
}
  • 若子进程已退出,调用wait/waitpid时,wait/waitpid会立即返回,并释放资源,获得子进程退出信息;
  • 如在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞;
  • 如不存在该子进程,则立即出错返回;

获取子进程status

  • wait/waitpid都有一个status参数,此参数为输出型参数,由操作系统填充;
  • 如传递NULL,表示不关心子进程的退出状态信息;否则,操作系统会根据该参数,将子进程发退出信息反馈给父进程;
  • status不能简单的当作整型看待,可当作位图,只研究低16位;

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    //创建子进程,睡眠2秒退出 
    pid_t id = fork();
    if(id<0)
    {                                                                          
        perror("fork");
        return 1;
    }
    else if(id==0)
    {
        sleep(5);
        printf("child:pid=%d, ppid=%d, id=%d\n",getpid(),getppid(),id);
        exit(1);
    }
    //父进程等待
    int status = 0;
    pid_t wait_pid = waitpid(id, &status, 0);
    printf("father:pid=%d, wait_pid=%d\n",getpid(), wait_pid);
    int stat = (status>>8) & 0xFF; //status二进制中8~15位;
    int sig = status & 0x7F; //status二进制中0~7位;
    sleep(3);
    printf("father finish!\n");
    return 0;
}

 注:

  • 不可通过设置全局变量,来告知父进程子进程的退出状态,因为父子进程相互独立,且写实拷贝;
  • waitpid获取的status值,是从子进程的task_struct中得到的;
  • 一般子进程提前终止,是该进程收到了OS发送的信号(信号中没有0,0就表示为正常终止,正常终止是没有收到任何退出信号 );
[wz@192 Desktop]$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Git】保姆级详解:Git配置SSH Key(密钥和公钥)到github

博主简介&#xff1a;22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a;是瑶瑶子啦每日一言&#x1f33c;: “当人们做不到一些事情的时候&#xff0c;他们会对你说你也同样不能。”——《当幸福来敲门》 克里斯加德纳 Git配置SSH Key 一、什么是Git?二、什么…

Shader 编程:GLSL 重要的内置函数

该原创文章首发于微信公众号&#xff1a;字节流动 未经作者&#xff08;微信ID&#xff1a;Byte-Flow&#xff09;允许&#xff0c;禁止转载 前面发了一些关于 Shader 编程的文章&#xff0c;有读者反馈太碎片化了&#xff0c;希望这里能整理出来一个系列&#xff0c;方便系统的…

二叉树OJ(C)

文章目录 1.单值二叉树1.1法一&#xff1a;无返回值1.2法二&#xff1a;有返回值 2.相同的树3.对称二叉树4.二叉树的前序遍历5.二叉树的中序遍历6.二叉树的后序遍历7.另一棵树的子树8.二叉树遍历 1.单值二叉树 1.1法一&#xff1a;无返回值 struct TreeNode {int val;struct …

docker端口映射详解(随机端口、指定IP端口、随意ip指定端口、指定ip随机端口)

目录 docker端口映射详解 一、端口映射概述&#xff1a; 二、案例实验&#xff1a; 1、-P选项&#xff0c;随机端口 2、使用-p可以指定要映射到的本地端口。 Local_Port:Container_Port&#xff0c;任意地址的指定端口 Local_IP:Local_Port:Container_Port 映射到指定地…

Java设计模式之工厂设计模式

简介 工厂模式是一种常见的设计模式&#xff0c;用于创建对象的过程中&#xff0c;通过工厂类来封装对象的创建过程。其核心思想是将对象的创建和使用分离&#xff0c;从而降低耦合度&#xff0c;提高代码的可维护性和可扩展性。工厂模式通常包括三种类型&#xff1a;简单工厂…

探索国产嵌入式Python解决方案的方法(开源)

大家好&#xff0c;今天我们要介绍一款适用于单片机的嵌入式Python开源项目 -- PikaPython。 第一&#xff1a;嵌入式Python的发展趋势 在嵌入式领域软硬件的发展趋势中&#xff0c;硬件的成本日益降低&#xff0c;性能逐渐提升。这种趋势使得Python在芯片上的运行难度已经大大…

【雕爷学编程】MicroPython动手做(28)——物联网之Yeelight 4

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

物联网平台使用笔记

阿里云的IOT平台限制了50个设备。排除 移动云的限制较少&#xff0c;这里试用下。 创建完产品&#xff0c;接入设备后。使用MQTT客户端测试 其中client id 为设备id&#xff0c; username 为产品id&#xff0c; password 可以使用设备调试那里生成的。或使用官方token.exe 生成…

7.1.tensorRT高级(2)-使用openvino进行onnx的模型推理过程

目录 前言1. openvino2. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-使用 openvino 进行 onnx…

ChatGPT3.5——AI人工智能是个什么玩意?

ChatGPT3.5——AI人工智能 AI人工智能什么是AI&#xff1f;AI有什么过人之处AI有什么缺点 AI的发展AI的发展史中国是如何发展AI的 AI六大要素感知理解推理学习交互 ChatCPT-3.5GPT-3.5的优势在哪里GPT-3.5的风险GPT-4骗人事件 AI人工智能 AI&#xff0c;就像是一位超级聪明的机…

地级市经济增长质量指数及原始数据(2006-2018年)

二十大报告强调&#xff0c;高质量发展是全面建设社会主义现代化国家的首要任务。研究表明&#xff0c;知识产权示范城市建设显著提高了城市经济增长质量&#xff0c;且这种促进作用具有持续性&#xff0c;地方政府财政支出偏向的改变以及知识产权司法保护和行政保护力度的提升…

关系型数据库的设计

范式 关系 注意&#xff1a;根据阿里开发规范&#xff0c;不再设置数据库的外键&#xff0c;在应用层保证外键逻辑即可 数据库设计 1:1 1:n 设想学生-班级案例&#xff0c;若在班级中保存所有学生的主键&#xff0c;则表长不好预测&#xff0c;表的数据亢余。 所以是在多的…

Maven设置阿里云路径(防止加载过慢)

<?xml version"1.0" encoding"UTF-8"?><!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding …

【雕爷学编程】Arduino动手做(184)---快餐盒盖,极低成本搭建机器人实验平台3

吃完快餐粥&#xff0c;除了粥的味道不错之外&#xff0c;我对个快餐盒的圆盖子产生了兴趣&#xff0c;能否做个极低成本的简易机器人呢&#xff1f;也许只需要二十元左右 知识点&#xff1a;轮子&#xff08;wheel&#xff09; 中国词语。是用不同材料制成的圆形滚动物体。简…

外卖多门店小程序开源版开发

外卖多门店小程序开源版开发 外卖多门店小程序开源版的开发可以按照以下步骤进行&#xff1a; 确定需求&#xff1a;明确外卖多门店小程序的功能和特点&#xff0c;包括用户注册登录、浏览菜单、下单支付、订单管理等。技术选型&#xff1a;选择适合开发小程序的技术框架&…

Pytest学习教程_测试报告生成pytest-html(三)

前言 pytest-html 是一个用于生成漂亮的 HTML 测试报告的 pytest 插件。它可以方便地将 pytest 运行的测试结果转换为易于阅读和理解的 HTML 报告&#xff0c;提供了丰富的测试结果展示功能和交互性。 一、安装 # 版本查看命令 pytest版本&#xff1a; pytest --version pyte…

Kubernetes 整体架构介绍

架构图 Kubernetes 主要由以下几个核心组件组成&#xff1a; etcd 保存了整个集群的状态&#xff1b;kube-apiserver 提供了资源操作的唯一入口&#xff0c;并提供认证、授权、访问控制、API 注册和发现等机制&#xff1b;kube-controller-manager 负责维护集群的状态&#xf…

SpringBoot 升级内嵌Tomcat

SpringBoot 更新 Tomcat 最近公司的一个老项目需要升级下Tomcat&#xff0c;由于这个项目我完全没有参与&#xff0c;所以一开始我以为是一个老的Tomcat项目&#xff0c;升级它的Tomcat依赖或者是Tomcat容器镜像&#xff0c;后面发现是一个SpringBoot项目&#xff0c;升级的是…

Rpc异步日志模块

Rpc异步日志模块作用 在一个大型分布式系统中&#xff0c;任何部署的分布式节点都可能发生崩溃&#xff0c;试想如果用普通的办法&#xff0c;即先排查哪个节点down掉了&#xff0c;找到down掉的节点后采取调试工具gdb调试该节点&#xff0c;进而排查宕机的原因。这中排查方法…

考研408 | 【计算机网络】物理层

导图&#xff1a; 一、通信基础 基本概念&#xff1a; 物理层接口特性&#xff1a;物理层解决如何在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。 物理层主要任务&#xff1a;确定与传输媒体接口有关的一些特性 典型的数据通信模型 数据通…