LinuxC编程——进程
目录
- 一、概念
- 1.1 程序
- 1.2 进程
- 二、特点⭐⭐⭐
- 三、进程段
- 四、进程分类
- 五、进程状态
- 六、进程状态转换图
- 七、函数接口
- 1. 创建子进程
- 2. 回收进程资源
- 3. 退出进程
- 4. 获取进程号
- 八、守护进程
一、概念
进程和程序是密不可分的两组概念,相对比,便于理解。
1.1 程序
简单来说,程序即编译好的可执行文件
展开来说:
- 编译好的可执行文件
- 存放在磁盘上的指令和数据的有序集合(文件)
- 静态的,没有执行的概念
1.2 进程
程序一次执行过程,是动态的,包括创建、调度、执行以及消亡,它是一个独立的可调度的任务
展开来说:
- 进程是程序的一次执行过程。
- 进程是动态的,包含创建、调度、执行、消亡。
- 进程是执行一个程序分配资源的总称。
- 独立的可调度的任务
二、特点⭐⭐⭐
- 系统会为每一个进程分配0-4g的虚拟空间,其中0-3g(用户空间)是每个进程所独有的,3g-4g(内核空间)是所有进程共有的。
- CPU调度进程时会给进程分配时间片(几毫秒 ~ 十几毫秒),当时间片用完后,cpu再进行其他进程的调度,实现进程的轮转,从而实现多任务的操作。
三、进程段
Linux中的进程包含三个段:
- “数据段”存放的是全局变量、常数以及动态数据分配的数据空间(如malloc函数取得的空间)等。
- “正文段”存放的是程序中的代码
- “堆栈段”存放的是函数的返回地址、函数的参数以及程序中的局部变量
四、进程分类
- 交互进程:该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行。该类进程经常与用户进行交互,需要等待用户的输入,当接收到用户的输入后,该类进程会立刻响应,典型的交互式进程有:shell命令进程、文本编辑器等
- 批处理进程:该类进程不属于某个终端,它被提交到一个队列中以便顺序执行。
- 守护进程:该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束。
五、进程状态
- 运行态(TASK_RUNNING)R:指正在被CPU运行或者就绪的状态。这样的进程被成为runnning进程。
- 睡眠态(等待态):
- 可中断睡眠态(TASK_INTERRUPTIBLE)S:处于等待状态中的进程,一旦被该进程等待的资源被释放,那么该进程就会进入运行状态。
- 不可中断睡眠态(TASK_UNINTERRUPTIBLE)D:该状态的进程只能用wake_up()函数唤醒。
- 暂停态(TASK_STOPPED)T:当进程收到信号SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU时就会进入暂停状态。可向其发送SIGCONT信号让进程转换到可运行状态。
- 死亡态X:进程结束
- 僵尸态(TASK_ZOMBIE)Z:当进程已经终止运行,但还占用系统资源,要避免僵尸态的产生(例如:在父子进程中,子进程比父进程先结束,而父进程没有对子进程及时回收,释放子进程占用的资源,此时子进程将变成一个僵尸进程)。
六、进程状态转换图
进程创建后,进程进入就绪态,当CPU调度到此进程时进入运行态,当时间片用完时,此进程会进入就绪态,如果此进程正在执行一些IO操作(阻塞操作)会进入阻塞态,完成IO操作(阻塞结束)后又可进入就绪态,等待CPU的调度,当进程运行结束即进入结束态。

七、函数接口
1. 创建子进程
pid_t fork(void);
-
功能:创建子进程
-
参数:无
-
返回值
- 成功:在父进程中:返回子进程的进程号 >0;在子进程中:返回值为0
- 失败:-1并设置errno
-
特点⭐⭐⭐
- 子进程几乎拷贝了父进程的全部内容,包括:代码、数据、系统数据段中的pc值、栈中的数据、父进程中打开的文件等;但它们的PID、PPID是不同的。
- 父子进程有独立的地址空间,互不影响;当在相应的进程中改变全局变量、静态变量,都互不影响。
- 若父进程先结束,子进程成为孤儿进程,被init进程收养,子进程变成后台进程。
- 若子进程先结束,父进程如果没有及时回收,子进程变成僵尸进程(要避免僵尸进程产生)
-
拓展:
- fork之前的代码被复制,但是不会重新执行一遍;fork之后的代码被复制,并且再被执行一遍。
- fork之后两个进程相互独立,子进程拷贝了父进程的所有代码,但内存空间独立
- fork之前打开文件,fork之后拿到的是同一个文件描述符,操作的是同一个文件指针。(而不同的进程打开相同的文件,操作的是不同的文件指针)
- fork函数创建父子进程后各自执行顺序不一定(vfork:先执行完子进程,再执行父进程)
-
例子:
#include <stdio.h>
#include <unistd.h>
// 若父进程先结束,子进程将变成孤儿进程 且被init进程收养,变成孤儿进程
// 若子进程先结束,父进程如果没与及时回收,子进程将变成僵尸进程
int main(int argc, char const *argv[])
{int a =0;pid_t pid = fork();if(pid<0){perror("fork err");return -1;}else if(pid == 0){ // 运行子进程printf("child a:%d\n",a);while(1);}else{ // 运行父进程a=3;printf("parent a:%d\n",a);//while(1);}return 0;
}
2. 回收进程资源
- wait:pid_t wait(int *status);
- 功能:回收子进程资源(阻塞)
- 参数
- status:子进程退出状态,不接受子进程状态设为NULL
- 返回值
- 成功:回收的子进程的进程号
- 失败:-1
- waitpid:pid_t waitpid(pid_t pid, int *status, int options);
- 功能:回收子进程资源
- 参数:
- pid:

- status:子进程退出状态
- options:
- 0:阻塞
- WNOHANG:非阻塞
- pid:
- 返回值
- 正常:结束的子进程的进程号
- 当使用选项WNOHANG且没有子进程结束时:0
- 出错:-1
- 例
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{int a = 0;pid_t pid = fork();if(pid<0){perror("fork err");return -1;}else if(pid == 0){printf("in child a=%d\n",a);// while(1);sleep(1);}else{a = 3;// wait(NULL); //阻塞回收所有子进程// waitpid(-1,NULL,0); //阻塞回收所有子进程waitpid(pid,NULL,0); // 阻塞回收pid进程// waitpid(pid,NULL,WNOHANG); //不阻塞回收进程号为pid的进程printf("in parent a = %d\n",a);// while(1);wait(NULL);printf("parent end...\n");}return 0;
}
3. 退出进程
- exit :void exit(int status);
- 功能:结束进程,刷新缓存
- 参数:退出的状态
- _exit:void _exit(int status);
- 功能:结束进程,不刷新缓存
- 参数:status是一个整型的参数,可以利用这个参数传递进程结束时的状态。
通常0表示正常结束;其他的数值表示出现了错误,进程非正常结束
注:exit与return的区别⭐⭐
- exit:函数,不管在子函数还是主函数,都可以结束进程(进程的退出)
- return:关键字,当子函数中有return时返回到函数调用位置,并不结束进程(函数的退出)
例子:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>void fun(int a, int b)
{printf("a+b=%d",a+b);// exit(0); // 结束进程,刷新缓存_exit(0); // 结束进程,不刷新缓存return;
}int main(int argc, char const *argv[])
{pid_t pid = fork();if(pid<0){perror("fork err");return -1;}else if(pid == 0){printf("in child\n");fun(3,4);sleep(1);}else{printf("in parent\n");// while(1);wait(NULL);printf("parent end...\n");}return 0;
}
运行结果:
exit:会刷新缓存

_exit:不会刷新缓存

4. 获取进程号
- getpid:pid_t getpid(void);
- 功能:获取当前进程的进程号
- getppid:pid_t getppid(void);
- 功能:获取当前进程的父进程号
例:
- 功能:获取当前进程的父进程号
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{pid_t pid = fork();if(pid<0){perror("fork err");return -1;}else if(pid == 0){printf("childpid:%d ppid:%d pid:%d\n",getpid(),getppid(),pid);exit(0);}else{printf("parentpid:%d ppid:%d pid:%d\n",getpid(),getppid(),pid);wait(NULL);}return 0;
}
运行:

练习:通过父子进程完成对文件的拷贝(cp),父进程从文件开始到文件的一半开始拷贝,子进程从文件的一半到文件末尾。要求:文件IO cp src dest
- 方法一
这里先执行子进程来进行源文件后半部分的复制,然后执行父进程来进行源文件前半部分的复制

方法二:
这里先执行父进程来进行源文件前半部分的复制,后执行子进程来进行源文件后半部分的复制
//通过父子进程完成对文件的拷贝(cp),父进程从文件开始到文件
//的一半开始拷贝,子进程从文件的一半到文件末尾。要求:文件IO cp src dest
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{if (argc != 3){printf("Please input:%s <srcfile> <destfile>\n", argv[0]);return -1;}int src = open(argv[1], O_RDONLY);if (src < 0){perror("srcfile open err");return -1;}int dest = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0666);if (dest < 0){perror("destfile open err");return -1;}off_t half = lseek(src, 0, SEEK_END) / 2; // 文件长度的一半int flag = 0; // 控制下面父子进程执行顺序,让父进程先执行ssize_t s;char buf[32] = {0};pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0) // 子进程 复制源文件后半部分{while (flag == 1) // 父进程已复制完毕,子进程可以执行{lseek(src, half, SEEK_SET);lseek(dest, half, SEEK_SET);while ((s = read(src, buf, 32)) != 0)write(dest, buf, s);}}else // 父进程 复制源文件前半部分(先执行){lseek(src, 0, SEEK_SET);lseek(dest, 0, SEEK_SET);int n = half;if (n < 32){read(src, buf, n);write(dest, buf, n);flag = 1;wait(NULL);}else{while ((s = read(src, buf, 32)) != 0){write(dest, buf, s);n = n - s;if (n < 32){read(src, buf, n);write(dest, buf, n);flag = 1;wait(NULL);}}}}close(src);close(dest);return 0;
}
//通过父子进程完成对文件的拷贝(cp),父进程从文件开始到文件
//的一半开始拷贝,子进程从文件的一半到文件末尾。要求:文件IO cp src dest
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{if (argc != 3){printf("Please input:%s <srcfile> <destfile>\n", argv[0]);return -1;}int src = open(argv[1], O_RDONLY);if (src < 0){perror("srcfile open err");return -1;}int dest = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0666);if (dest < 0){perror("destfile open err");return -1;}off_t half = lseek(src, 0, SEEK_END) / 2; // 文件长度的一半int flag = 0; // 控制下面父子进程执行顺序,让父进程先执行ssize_t s;char buf[32] = {0};pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0) // 子进程 复制源文件后半部分{while (flag == 1) // 父进程已复制完毕,子进程可以执行{lseek(src, half, SEEK_SET);lseek(dest, half, SEEK_SET);while ((s = read(src, buf, 32)) != 0)write(dest, buf, s);}}else // 父进程 复制源文件前半部分(先执行){lseek(src, 0, SEEK_SET);lseek(dest, 0, SEEK_SET);int n = half;if (n < 32){read(src, buf, n);write(dest, buf, n);flag = 1;wait(NULL);}else{while ((s = read(src, buf, 32)) != 0){write(dest, buf, s);n = n - s;if (n < 32){read(src, buf, n);write(dest, buf, n);flag = 1;wait(NULL);}}}}close(src);close(dest);return 0;
}
八、守护进程
- 特点
守护进程是后台进程;生命周期比较长,从系统启动时开启,系统关闭时结束;它是脱离控制终端且周期执行的进程。 - 实现步骤
- 创建子进程,父进程退出
让子进程成为孤儿进程,成为后台进程。fork - 在子进程中创建新会话
让子进程成为会话组组长,为了让子进程脱离控制终端。setsid() - 改变运行路径为根目录。chdir
原因:提高权限,让运行路径不能被删除或卸载。chdir - 重设权限掩码。umask
目的:增大进程创建文件的权限,提高灵活性。umask - 关闭不必要的文件描述符
目的:关闭不必要的文件描述符。close
- 创建子进程,父进程退出
- 练习:创建一个守护进程,循环间隔1s向文件中写入一串字符“hello”
/*创建守护进程实现往日志文件中循环写入hello,间隔时间为1秒*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>int main(int argc, char const *argv[])
{//1.创建父子进程pid_t pid = fork();if(pid < 0){perror("fork err");return -1;}else if(pid == 0) //子进程进入{setsid(); //2.在子进程中创建新会话,让子进程成为会话组组长chdir("/"); //3.改变运行目录为根目录umask(0); //4.重设文件掩码close(0);//5.关闭文件描述符->0 1 2close(1);int fd = open("/tmp/c.log",O_WRONLY|O_CREAT|O_APPEND,0666);if(fd < 0){perror("open err");return -1;}}else{exit(0); //1.父进程退出}return 0;
}
相关文章:
LinuxC编程——进程
目录 一、概念1.1 程序1.2 进程 二、特点⭐⭐⭐三、进程段四、进程分类五、进程状态六、进程状态转换图七、函数接口1. 创建子进程2. 回收进程资源3. 退出进程4. 获取进程号 八、守护进程 一、概念 进程和程序是密不可分的两组概念,相对比,便于理解。 1.…...
深入理解设计模式-结构型之适配器
适配器模式(Adapter Pattern): 适配器模式用于将一个类的接口转换成另一个类的接口,以使两者能够一起工作。适配器模式通常用于处理已经存在的类,让它们能够与其他类协同工作,而不需要修改原始类的代码。&…...
桥梁结构健康监测系统,智能预警降低桥梁安全隐患
桥梁通常位于现代综合交通网络中的咽喉部位,对区域经济发展起着重要的推进作用,然而在为社会经济发展做出巨大贡献的同时,它们不可避免地会在荷载作用、环境侵蚀和自然灾害等影响下出现材料腐蚀劣化、结构损伤开裂、性能退化和功能失效等损伤…...
夏威夷等全球多地深陷「末日狂烧」,关键时刻 AI 监测能否跑赢野火?
内容一览:当地时间 8 月 8 日,美国夏威夷州突发野火,当地居民和游客不得不跳入太平洋中躲避火势。截至 8 月 17 日,这场野火已经造成110 人死亡,超过 1000人失踪。与此同时,美国、加拿大、法国等地也正遭遇…...
解决多模块内核心模块有接口打包成jar后被依赖并调用遇到的问题(springcloud集成ruoyi.quartz)
项目准备开发个新功能,刚好很喜欢ruoyi写的任务调度,因此想到了集成ruoyi.quartz模块 ,遇到了很多问题: 首先因为ruoyi.quartz模块依赖了ruoyi.common模块,因此第一步我需要把common模块一部分依赖项复制到了quartz模块内…...
【kubernetes系列】Kubernetes之Kubelet运行机制和状态更新机制
Kubelet运行机制 Kubelet是Kubernetes中的一个重要组件,在每个 Node 节点上都会启动 kubelet 服务。 该服务主要用于处理 Master 节点下发到本节点的任务,管理 Pod及Pod 中的容器。每个kubelet 进程会在 API Server 上注册节点自身信息,定期…...
(学习笔记-进程管理)怎么避免死锁?
死锁的概念 在多线程编程中,我们为了防止多线程竞争共享资源而导致数据错乱,都会在操作共享资源之前加上互斥锁,只有成功获得到锁的线程,才能操作共享资源,获取不到锁的线程就只能等待,直到锁被释放。 那…...
【golang】链表(List)
List实现了一个双向链表,而Element则代表了链表中元素的结构。 可以把自己生成的Element类型值传给链表吗? 首先来看List的四种方法。 MoveBefore方法和MoveAfter方法,它们分别用于把给定的元素移动到另一个元素的前面和后面。 MoveToFro…...
android平台的语音聊天助手源码
目录 1 android平台的语音聊天助手源码 1.1 //js处理工具类 1.1.1 openImage 1.2 LoadWebDetails android平台的语音聊天助手源码package com.shrimp.xiaoweirobot.net; import java.util.ArrayList;...
Python读取Word统计词频输出到Excel
1.安装依赖的包 "# 读取docx\n", "!pip install python-docx\n", "!pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python-docx\n", "# 中英文分词\n", "!pip install jieba\n", "!pi…...
windows docker mysql8.0 挂载配置文件不生效的问题
原因 mysql 8.0 遇到sql_modeonly_full_group_by的问题,于是就自定义my.cnf 去掉only_full_group_by,修改my.cnf 文件后,进行映射启动 docker run 命令 docker run -p 3306:3306 --privilegedtrue --restartalways -d --name axsc-mysql -…...
openGauss学习笔记-42 openGauss 高级数据管理-触发器
文章目录 openGauss学习笔记-42 openGauss 高级数据管理-触发器42.1 语法格式42.2 参数说明42.3 示例 openGauss学习笔记-42 openGauss 高级数据管理-触发器 触发器会在指定的数据库事件发生时自动执行函数。 42.1 语法格式 创建触发器 CREATE TRIGGER trigger_name { BEFORE…...
Leetcode33 搜索旋转排序数组
题解: /*** 旋转排序数组可分为N1 N2两个部分,如:[4,5,6,7,1,2,3],N1为[4,5,6,7],N2为[1,2,3]** 必然满足以下两个条件:* 1. N1和N2都是分别递增的;* 2. N1中的所有元素大于N2中的所有元素;** …...
docker 第一章
目录 1.安装 docker 2.镜像、容器 3.总结 1.安装 docker 2.镜像、容器 3.总结 容器在 linux 上的本机运行,与其他容器共享主机的内核。它运行的是一个独立的进程,不占用其他任何可执行文件的内存,非常轻量级。...
注册中心 —— SpringCloud Netflix Eureka
Eureka 简介 Eureka 是一个基于 REST 的服务发现组件,SpringCloud 将它集成在其子项目 spring-cloud-netflix 中,以实现 SpringCloud 的服务注册与发现,同时提供了负载均衡、故障转移等能力,目前 Eureka2.0 已经不再维护…...
2023年国赛数学建模思路 - 案例:异常检测
文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 建模资料 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常…...
⛳ Java 反射
目录 ⛳ Java 反射🎨 一、反射概述**🎃 使用反射的前提条件: **🎲 类正常加载过程如下图:反射优缺点:🧸 Java反射机制提供的功能: **🥅 反射主要API** 🏭 二、反射的使用Ἲ…...
Android 13 像Settings一样开启关闭深色模式
一.背景 由于客户定制的Settings需要开启关闭深色模式,所以需要自己调用开启关闭深色模式 二.前提条件 首先应用肯定要是系统应用,并且导入framework.jar包,具体可以参考: Android 应用自动开启辅助(无障碍)功能并使用辅助(无障碍)功能_android 自动开启无障碍服务_龚礼鹏…...
微服务实战项目-学成在线-项目优化(redis缓存优化)
微服务实战项目-学成在线-项目优化(redis缓存优化) 1 优化需求 视频播放页面用户未登录也可以访问,当用户观看试学课程时需要请求服务端查询数据,接口如下: 1、根据课程id查询课程信息。 2、根据文件id查询视频信息。 这些接口在用户未认…...
IDEA 找不到项目 ‘org.springframework.boot:spring-boot-starter-parent:3.1.2‘
找不到项目 ‘org.springframework.boot:spring-boot-starter-parent:2.6.7’ 这个问题主要是因为ide的缓存导致的,我们直接清理缓存并重启ide 重启之后ide会对pom文件进行编排索引完成之后问题就没有了...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
