(八)Linux的进程与线程
多任务处理是指用户可以在同一时间内运行多个应用程序,每个正在执行的程序被称为一个任务。一个任务包含一个或多个完成独立功能的子任务,其中子任务可以是进程或线程。Linux就是一个支持多任务的操作系统,比起单任务系统它的功能增强许多。
一.进程
进程:一个具有独立功能的程序在某个数据集合上的一次动态执行过程,它是操作系统进行资源分配和调度的基本单元。一次任务的运行可以激活多个进程,进程相互合作来完成该任务的一个最终目标。
进程和程序区别:
1)程序是一段静态的代码,是保存在非易失性的存储器上的指令和数据的有序集合,没有任何执行的概念。
2)进程是一个动态的概念,它是程序的一次执行过程,包括了动态创建、调度、执行和消亡的整个过程,它是程序执行和资源管理的最小单位。
Linux系统中主要下面几种类型的进程。
进程 | 说明 |
---|---|
交互性进程 | 常与用户进行交互,需要等待用户的输入。当接收到用户的输入之后进程立即响应,如Shell命令进程、文本编辑器和图形应用程序运行 |
批处理进程 | 不用进行交互,通常在后台运行,不必快速响应,不会优先调度。如编译器的编译操作、数据库搜索引擎 |
守护进程 | 一直在后台运行,和任何终端都不关联。通常系统启动时开始执行,系统关闭时才开始 |
进程具有以下几个主要性质
性质 | 说明 |
---|---|
并发性 | 系统多个进程可以同时并发执行,相互之间不受干扰 |
动态性 | 进程都有完整的生命周期,而且在进程的生命周期中,进程状态是不断变化的,进程具有动态的地址空间 |
交互性 | 进程在执行过程中会与其它进程发生直接和间接的通信,如进程同步和进程互斥等,需要为此添加一定的进程处理机制 |
独立性 | 进程是相对完整的资源分配和调度的基本单元,各个进程的地址空间是相互独立的 |
进程不但包括程序的指令和数据,而且包括程序计数器和处理器的所有寄存器以及存储临时数据的进程堆栈。Linux内核取得处理器的控制权,按照某种调度算法将处理器分配给某个正在等待执行的进程。内核将所有的进程存放在双向循环链表(进程链表)中,链表的每一项都是task_struct,称为进程控制块的结构,其在<include/Linux/sched.h>文件中定义。task_struct 内核比较大,它能完整描述一个进程,如进程的状态、进程的基本信息、进程标识符、内存相关信息、父进程相关信息、与进程相关的终端信息、当前工作目录、打开的文件信息、所接收的信号信息等。
task_struct结构中最为重要的两个域:state(进程状态)和pid(进程标识符)
(1)进程状态
Linux中进程的几个主要状态如下:
进程状态 | 说明 |
---|---|
运行状态 | 进程正在运行,或者正在运行队列中等待调度 |
可中断的阻塞状态 | 进程处于阻塞(睡眠)状态,正等待某些事情发生或者占用某些资源。处于这种状态的进程可被信号中断。接收到信号可被唤醒。唤醒之后变为运行状态 |
不可中断的阻塞状态 | 不会处理信号,只有等待的事情发生时,进程才能被显式呼叫唤醒 |
暂停状态 | 进程的执行被暂停,当收到暂停信号才进入暂停 |
僵死状态 | 子进程运行结束,父进程未退出,并且未使用wait函数族等系统来调用来回子进程的退出状态。 |
消亡状态 | 最终状态,父进程调用wait函数族回收后,子进程彻底由系统删除,不可见。 |
(2)进程标识符与进程命令
Linux内核通过唯一的进程标识符PID来标识每一个进程。系统创建的进程数目有限制,可以查看/proc/sys/kernel/pid_max/来确定上限。
命令 | 说明 |
---|---|
current->pid ,top | 用来记录正在运行的进程 |
for_each_process,ps -l/-e/-f | 查看所有进程 |
getpid | 获得当前进程的进程号 |
getppid | 获得当前进程的父进程号 |
jobs | 查看后台进程 |
bg | 将挂起的进程在后台运行 |
fg | 把后台运行的进程放到前台运行 |
nice | 按用户指定的优先级运行进程 |
renice | 改变正在运行进程的优先级 |
/proc | 查看进程详细信息 |
(3)进程的创建、执行和终止
首先在新的地址空间里创建进程、读入可执行文件,最后再开始执行。Linux中进程的创建分解到fork()和exec函数族执行。fork()通过复制当前进程创建一个子进程,exec函数族负责读取其载入地址空间开始运行。
子进程与父进程的区别:不同的PID、PPID和某些资源及统计量
进程终止时系统需保证进程所占用的资源回收,并通知父进程。Linux首先把终止的进程设置为僵死状态,进程无法运行,只能为父进程提供信息。父进程在某个时间调用wait函数族,回收子进程的退出状态,然后子进程占用的所有资源被释放。
(4)进程的内存管理
Linux操作系统采用虚拟内存空间管理技术,使得每个进程都具有独立的地址空间,该地址空间是大小为4GB的线性虚拟空间。4GB的进程地址空间分为用户空间和内核空间。用户空间是0~3GB,内核地址空间占3-4GB。用户进程只能访问用户空间的虚拟地址,只有使用系统调用时才能访问内核空间。
用户空间包括以下几个功能区域(称段)
段 | 说明 |
---|---|
只读段 | 具有只读性质,包括程序代码(.init和.text)和只读数据 (.rodata) |
数据段 | 存放的是全局变量和静态变量,初始化段(.data和.bss)和未初始化段 |
栈 | 由系统自动分配释放存放函数的参数值、局部变量的值和返回地址等 |
堆 | 存放动态分配的数据,一般由程序员动态分配和释放,若不释放,程序结束可由系统回收 |
共享库的内存映射区域 | Linux动态链接器和其它共享库代码 |
二.进程编程
(1)进程创建:fork()函数
fork()函数用于从一个已存在进程中创建一个新进程,新进程是原进程的子进程。
父进程:进程上下文、代码段、进程堆栈、内存信息、打开的文件描述符、信号处理函数、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等
子进程:除父进程还有它的进程号、资源使用和计数器等
父子进程的区别:fork()的返回值不同。父进程返回子进程的进程号,子进程返回0
#include<sys/types.h>
#include<unistd.h>
pid_t fork()
返回值:子进程PID(大于0的整数)->父进程:0->子进程:-1->出错
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>int main(void){pid_t ret;ret=fork();if(ret== -1)
{perror("fork error");return -1;
}
else if (ret == 0)
{printf("In child process!!ret is %d,My PID is %d\n",ret,getpid());
}
else
{printf("In parent process !! ret is %d,My PID is %d\n",ret,getpid());
}
return 0;
}
In parent process !! ret is 32189,My PID is 32188
In child process!!ret is 0,My PID is 32189
若父进程先结束,子进程成为孤儿进程,被init进程收养,子进程变成后台进程
若子进程先结束,父进程如果没有及时回收,子进程变成僵尸进程
(2)exec函数族
exec函数组提供了一个在进程中执行另一个程序的方法,它可以根据指定文件名或者目录名找到可执行文件,并用它来取代当前进程的数据段、代码段和堆栈段。执行完后,当前进程除了进程号外,其它内容都被替换。
在Linux中使用exec函数族主要两种情况:
1)当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec()函数族中的任意一个函数让自己重生。
2)如果一个进程想执行另一程序,那么它就可以调用fork()函数新建一个进程,然后调用exec( )函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个进程。
进程调用exec函数族执行某个程序
进程当前内容被指定的程序替换
实现让父子进程执行不同的程序:
父进程创建子进程
子进程调用exec函数族
父进程不受影响
#include<unistd.h>
int execl(const char *path ,const char *arg,...);
int execv(const char *path ,char *const argv[]);
int execle(const char *path,const char *arg,...,char *const envp[]);
int execve(const char *path,const char *arg,...,char *const envp[]);
int execlp(const char *file,const char *arg,...);
int execvp(const char *file,char *const argv[]);
返回值-1:出错
函数名 | 含义 |
---|---|
前4位 | exec |
第五位 | l:参数传递为逐个列举,v:参数传递为构造数组指针数组 |
第六位 | e:可传递新进程环境变量,p:可执行文件查找方式为文件名 |
实际上,这6个函数中真正的系统调用只有execve(),其它5个都是库函数,它们最终都会调用execve()这个系统调用。在使用exec函数族时,要加入错误判断语句。exec很容易执行失败,常见原因如下:
1)找不到文件或路径,此时errno被设置为ENOENT
2)数组argv和envp忘记用NULL结束,此时errno被设置为EFAULT
3)没有对应可执行的运行权限,此时errno被设置为EACCES
执行ls命令,显示/etc目录下所有文件的详细信息if (execl(“/bin/ls”, “ls”, “-a”, “-l”, “/etc”, NULL) < 0) {perror(“execl”);} if (execlp(“ls”, “ls”, “-a”, “-l”, “/etc”, NULL) < 0) {perror(“execlp”);}
执行ls命令,显示/etc目录下所有文件的详细信息char *arg[] = {“ls”, “-a”, “-l”, “/etc”, NULL};if (execv(“/bin/ls”, arg) < 0) {perror(“execv”);} if (execvp(“ls”, arg) < 0) {perror(“execvp”);}
(3)进程退出:exit()和_exit()
exit()和_exit()函数都是用来终止进程的。当程序执行到exit()和_exit()时,进程会无条件地停止剩下的所有操作,清除各种数据结构,并终止本进程的运行。但是,这两个函数还是有区别的。_exit()函数的作用是直接使进程停止运行,清除其使用的内存空间,并清除其在内核中的各种数据结构;exit()函数则在这些基础上做了一些包装,在执行退出之前加入了若干道工序。它们最大区别是终止当前进程之前,有无进行清理I/O缓冲。
#include<stdlib.h>
void exit(int status);返回值:0表示正常结束,其它表示进程非正常结束
#include<unistd.h>
void _exit(int status);
#include <stdio.h>#include <stdlib.h>int main(void) {printf(“this process will exit”);exit(0);printf(“never be displayed”);}```c
./a.out this process will be exit
(4)进程回收:wait()和waitpid()
wait()函数用于使父进程(调用wait()的进程)阻塞,直到一个子进程结束或者该进程接收到一个指定信号为止。如果该父进程没有子进程或者他的子进程已经结束,则wait()会返回-1。waitpid的作用和wait()一样,但它并不一定等待第一个终止的子进程。waitpid()有若干个选项,可以提供一个非阻塞的wait()功能。
子进程结束时由父进程回收,孤儿进程由init进程回收,若没有及时回收会出现僵尸进程。
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *status);
成功:已回收的子进程的进程号
失败:-1
#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid,int *status,int options);
pid>0:回收进程ID等于pid的子进程
pid=-1:回收任何一个子进程
pid=0:回收其组ID等于调用进程的组ID的任一子进程
pid<-1:回收其组ID等于pid的绝对值的任一子进程
options:WNOHANG->若指定的子进程没有结束,则waitpid()不阻塞而立即返回,此时返回值为0
option:WUNTRACED->为了实现某种操作,由pid指定的任一子进程已暂停,且其状态自暂停以来还未报告过,则返回其状态。
>0:已经结束运行的子进程的进程号
0:使用选项WNOHANG且没有子进程退出
-1:出错
waitpid(pid, &status, 0);waitpid(pid,
相关文章:

(八)Linux的进程与线程
多任务处理是指用户可以在同一时间内运行多个应用程序,每个正在执行的程序被称为一个任务。一个任务包含一个或多个完成独立功能的子任务,其中子任务可以是进程或线程。Linux就是一个支持多任务的操作系统,比起单任务系统它的功能增强许多。 一.进程 进程:一个具有独立功…...

Map-JAVA面试常问
1.HashMap底层实现 底层实现在jdk1.7和jdk1.8是不一样的 jdk1.7采用数组加链表的方式实现 jdk1.8采用数组加链表或者红黑树实现 HashMap中每个元素称之为一个哈希桶(bucket),哈希桶包含的内容有以下4项 hash值(哈希函数计算出来的值) Key value next(…...

prometheus+grafana搭建监控系统
1.prometheus服务端安装 1.1下载包 使用wget下载 (也可以直接去官网下载包Download | Prometheus) wget https://github.com/prometheus/prometheus/releases/download/v2.44.0/prometheus-2.44.0.linux-amd64.tar.gz1.2解压 tar xf prometheus-2.44…...

flink学习-flink sql
动态表 在flink的数据处理中,数据流是源源不断的,是无界的,所以对于flink处理的数据表是一张动态表,所以对于动态表的查询也是持续的,每接收一条新数据会进行一次新的查询。 持续查询 因为数据在一直源源不动的到来…...

高考填报志愿攻略,5个步骤选专业和院校
在高考完毕出成绩的时候,很多人会陷入迷茫中,好像努力了这么多年,却不知道怎么规划好未来。怎么填报志愿合适?在填报志愿方面有几个内容需要弄清楚,按部就班就能找到方向,一起来了解一下正确的步骤吧。 第…...

Kubernetes排错(十)-处理容器数据磁盘被写满
容器数据磁盘被写满造成的危害: 不能创建 Pod (一直 ContainerCreating)不能删除 Pod (一直 Terminating)无法 exec 到容器 如何判断是否被写满? 容器数据目录大多会单独挂数据盘,路径一般是 /var/lib/docker,也可能是 /data/docker 或 /o…...

使用QtGui显示QImage的几种方法
问题描述 我是一名刚学习Qt的新手,正在尝试创建一个简单的GUI应用程序。当点击一个按钮时,显示一张图片。我可以使用QImage对象读取图片,但是否有简单的方法调用一个Qt函数,将QImage作为输入并显示它? 方法一:使用QLabel显示QImage 最简单的方式是将QImage添加到QLabe…...

C++ lamda
1 lamada 的函数指针存在哪里?需要通过分析编译后的二进制; 2 捕获了什么? 为什么捕获?捕获的范围是什么? 捕获的生命周期是什么? lambda 定义匿名函数,使得代码更加灵活简洁; lam…...

Linux_应用篇(27) CMake 入门与进阶
在前面章节内容中,我们编写了很多示例程序,但这些示例程序都只有一个.c 源文件,非常简单。 所以,编译这些示例代码其实都非常简单,直接使用 GCC 编译器编译即可,连 Makefile 都不需要。但是,在实…...

51单片机STC89C52RC——8.1 8*8 LED点阵模块(点亮一个LED)
目录 目的/效果 一,STC单片机模块 二,8*8 LED点阵模块 2.1 电路图 2.1.1 8*8 点阵模块电路图 2.1.2 74HC595(串转并)模块 电路图 2.1.3 芯片引脚 2.2 引脚电平分析 2.3 74HC595 串转并模块 2.3.1 装弹(移位…...

2024最新免费版轻量级Navicat Premium Lite 下载和安装教程
2024最新免费版轻量级Navicat Premium Lite 下载和安装教程 关于猫头虎 大家好,我是猫头虎,别名猫头虎博主,擅长的技术领域包括云原生、前端、后端、运维和AI。我的博客主要分享技术教程、bug解决思路、开发工具教程、前沿科技资讯、产品评…...

PHP+laravel 生成word
此功能较为繁琐我会从源头讲起 首先是数据库设置,下面是我的数据库结构 合同模版表 CREATE TABLE contract_tpl (id bigint unsigned NOT NULL AUTO_INCREMENT,name varchar(191) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 合同名称,file varchar(191) COLL…...

redis集群简单介绍及其搭建过程
Redis集群 1、哨兵模式 哨兵可以有多个,从服务器也可以有多个,从服务器也可以有多个,在Redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会实现主从切换&#x…...

linux桌面运维----第五天
1、创建用户命令useradd: 作用:创建用户 语法:useradd [选项名] 用户名 选项: -d<登入目录> 指定用户登入时的起始目录。 【掌握】 -g<群组> 指定用户所属的群组(基本组)。【掌握】…...

【SQL Server数据库】简单查询
目录 用SQL语句完成下列查询。使用数据库为SCHOOL数据库 1. 查询学生的姓名、性别、班级名称,并把结果存储在一张新表中。 2. 查询男生的资料。 3. 查询所有计算机系的班级信息。 4.查询艾老师所教的课程号。 5. 查询年龄小于30岁的女同学的学号和姓名。…...

Docker 从入门到精通(大全)
一、概述 1.1 基本概念 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。…...

基于JSP的在线教育资源管理系统
开头语: 你好呀,我是计算机学长猫哥!如果你对在线教育资源管理系统感兴趣或者有相关需求,欢迎在文末找到我的联系方式。 开发语言:Java 数据库:MySQL 技术:JSP技术 工具:IDE、N…...

在java中代理http请求,如何避免陷入循环?
在 Java 中,代理 HTTP 请求时,如果不小心配置不当,可能会导致循环请求。循环请求通常发生在代理服务器将请求再次发送回自己,形成一个死循环。为了避免这种情况,可以采取以下几种方法: 将域名设置为指定的…...

国内镜像源网址
腾讯:腾讯软件源 (tencent.com) 阿里:阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 (aliyun.com) 清华:清华大学开源软件镜像站 | Tsinghua Open Source Mirror...

合适的智能猫砂盆到底怎么挑?开放式封闭式一次说清!
想当初我也是在网上看了各种测评,纠结了好久才下定决心入手了智能猫砂盆。封闭式和开放式都用过,各有各的利与弊,不过最后的我还是选择了开放式的智能猫砂盆,因为开放式的设计结构会更加方便我观察小猫,哪个铲屎官不喜…...

阿里云开启ssl证书过程记录 NGINX
🤞作者简介:大家好,我是思无邪,2024 毕业生,某厂 Go 开发工程师.。 🐂我的网站:https://www.yishanicode.top/ ,持续更新,希望对你有帮助。 🐞如果文章或网站…...

C语言程序设计 9.37 调用随机函数为5x4的矩阵置 100以内的整数,输出该矩阵,求出每行元素之和,并把和的最大的那一行与第一行的元素对调
void count_sum(int sum[]) {int i;printf("每行相加的情况如下\n");for (i 0;i < 5; i){printf("%d ", sum[i]);}printf("\n"); } void test(int arr[5][4]) {int i, j;srand((unsigned)time(NULL));//添加这个可以每次不同的随机数&#x…...

Webpack: 借助 Babel+TS+ESLint 构建现代 JS 工程环境
概述 Webpack 场景下处理 JavaScript 的三种常用工具:Babel、TypeScript、ESLint 的历史背景、功能以及接入 Webpack 的步骤借助这些工具,我们能构建出更健壮、优雅的 JavaScript 应用 使用 Babel ECMAScript 6.0(简称 ES6) 版本补充了大量提升 JavaSc…...

孩子不想上学,父母应如何教育?“强迫教育”会激起孩子反抗心理
上周末朋友聚会,都是家有上学娃的年纪,闲聊中,话题自然少不了孩子的上学问题。其中,不少朋友都有抱怨过同一个问题:孩子不想上学,即使人到了学校,心也不在学校。 事实上,孩子出现…...

Python深度学习技术
原文链接:Python深度学习技术 近年来,伴随着以卷积神经网络(CNN)为代表的深度学习的快速发展,人工智能迈入了第三次发展浪潮,AI技术在各个领域中的应用越来越广泛。Transformer模型(BERT、GPT-…...

ECharts 雷达图案例002 - 诈骗性质分析
ECharts 雷达图案例002 - 诈骗性质分析 📊 ECharts 雷达图案例002 - 诈骗性质分析 深入挖掘数据背后的故事,用可视化手段揭示诈骗行为的模式和趋势。 🔍 案例亮点 创新的数据展示方式,让复杂的诈骗数据一目了然。定制化的雷达图…...

想远程控制手机,用哪个软件好?
很多人都想知道安卓系统或iOS系统要如何实现手机远程控制手机、电脑远程控制手机,分别需要用到什么软件,这篇文章一次说清楚。 注意,安卓系统需要是7.0及以上版本,iOS系统需要是11及以上版本。具体使用步骤请点击关注,…...

数字内容“遍地开花”,AI技术如何创新“造梦”?
文 | 智能相对论 作者 | 陈泊丞 这是春晚舞台西安分会场《山河诗长安》的一幕:“李白”现世,带领观众齐颂《将进酒》,将中国人骨子里的豪情与浪漫演绎得淋漓尽致。 这又是浙江义乌商品市场里的另一幕:只会说几个英文单词的女老板…...

MySQL集群如何实现读写分离
数据源配置:定义了主从数据库的连接池。读写分离规则:通过MasterSlaveRuleConfiguration定义了主从数据库的读写分离规则。负载均衡算法:定义了从数据库的负载均衡算法。创建ShardingDataSource:使用数据源和读写分离规则创建了Sh…...

一分钟剪辑1000条视频的云微客矩阵,怎么做到的?
当我们打开短视频软件时,就会有大量风格迥异的短视频犹如潮水般涌现在我们面前,这些短视频不仅配置了加粗的标题,下方还配置了字幕,中间则播放着视频,就是这样简易的视频,往往总能获得较高的播放量…...