当前位置: 首页 > news >正文

【Linux】进程控制:创建、终止、等待与替换全解析

文章目录

  • 前言
  • 一、重谈进程创建
  • 二、进程终止
    • 2.1 正常终止的退出码机制
    • 2.2 异常终止的信号机制
    • 2.3 进程常见的退出方法
  • 三、进程等待:避免僵尸进程的关键
    • 3.1 进程等待的必要性
    • 3.2 进程等待的两个系统调用接口
      • 3.2.1 wait()
      • 3.2.2 waitpid()
      • 区别
  • 四、进程程序替换
    • 4.1 进程替换原理(单进程)
    • 4.2 多进程版程序替换效果——验证程序替换接口
    • 4.3 进程替换的接口
  • 总结


前言

本文将用最直白的语言带你掌握Linux进程管理的四大核心操作!包含大量代码示例与图解,建议边看边动手实践!


一、重谈进程创建

当我们使用fork()系统调用创建子进程时,父子进程的执行顺序并非固定,而是由操作系统的进程调度器决定。这种不确定性源于现代操作系统的并发特性

可能输出结果:
父进程PID: 1234
子进程PID: 1235或
子进程PID: 1235
父进程PID: 1234

1.2 调度机制解析

调度策略说明典型系统
完全公平调度(CFS)基于虚拟运行时间分配CPU时间片Linux默认
实时调度优先级驱动嵌入式系统
轮转调度均分时间片早期Unix系统

二、进程终止

2.1 正常终止的退出码机制

为什么main函数总是return 0 返回,这个0去哪里了?为什么

进程退出场景:

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码异常终止

在程序运行期间,我们通常并不关心意料之中的【程序正常运行且结果正确】的情况,反而那些结果有误、异常退出的情况能够让程序员及时发现问题原因并解决它。
程序中的return 0表示的是进程的退出码,表示进程的运行结果是否正确

此外,在系统层面上,进程运行时,一般来说是父进程最关心自己的子进程的运行状态,所以退出码是直接向父进程呈现的。
换言之,在子进程正常运行且退出时(返回0),父进程并不关心,更多的是关心子进程运行失败的原因并转交给用户,此时,程序就可以用return返回不同的值,来表示不同的出错原因。

我们可以使用以下指令来查看最近一次运行的进程返回的退出码是多少:

$ echo $? # $?表示最近一个程序运行的退出码

此外,在C语言中有将退出码转化为错误信息的strerror()函数

//打印所有退出码表示的信息
#include <string.h>int main()
{int i = 0;for(; i<200; i++){printf("%d: %s\n",i,strerror(i));}return 0;
}

在这里插入图片描述
此外,在我们平常使用的cd指令、pwd指令等,底层实现也是一段程序,同样会返回错误码信息:

举例: ls 不存在的目录时,返回2错误码
(No such file or directory)

在这里插入图片描述

2.2 异常终止的信号机制

在进程运行时,正常的顺序是先检查是否异常,再判断结果信息,只要是程序异常终止了,退出码就没有任何意义了。例如野指针问题或者除0错误等都会触发硬件级的异常问题,操作系统会直接给进程返回某种信号结束进程(kill)。
【这部分的内容我们会在后面的信号章节详细为大家讲解】

信号说明触发场景
SIGSEGV11段错误非法内存访问
SIGFPE8算术异常除零操作
SIGKILL9强制终止kill -9

2.3 进程常见的退出方法

  1. return 0(在 main 函数中)
    在 main 函数中使用 return 0 表示程序正常终止,返回值 0 作为进程的退出状态码。

触发 main 函数的隐式 exit 调用,
执行标准库的清理工作(如刷新 I/O 缓冲区、关闭文件流)。
最终通过系统调用(如 _exit)终止进程。

int main() {printf("Hello"); // 无换行符,但 return 会刷新缓冲区return 0;        // 输出 Hello
}
  1. exit(int status)
    标准库函数(stdlib.h),立即终止进程,返回状态码 status

刷新所有标准 I/O 缓冲区(如 printf 未输出的内容)。
关闭所有打开的流(FILE 类型)。
最终调用 _exit 终止进程。

#include <stdlib.h>
void func() {printf("World");  // 无换行符exit(0);          // 输出 World
}
  1. _exit(int status)
    系统调用(unistd.h),直接终止进程,返回状态码 status

不执行任何清理:
不刷新 I/O 缓冲区(可能导致数据丢失)。
不调用 atexit 注册的函数。
立即终止进程。

#include <unistd.h>
int main() {printf("Hello");  // 无换行符_exit(0);         // 无输出(缓冲区未刷新)
}

在这里插入图片描述

方式所属库/系统调用清理操作(I/O 缓冲区、atexit 函数)适用场景
return 0C 标准库是(隐式调用 exit)main 函数正常退出
exit()C 标准库任意位置终止并清理资源
_exit()系统调用快速终止,避免干扰(如子进程)

三、进程等待:避免僵尸进程的关键

通过系统调用wait / waitpid,来对子进程进行状态检测与回收的功能。

3.1 进程等待的必要性

  1. 避免僵尸进程(Zombie Process)
    子进程退出后,若父进程未调用等待函数,子进程的退出状态会残留在内核中,成为僵尸进程(占用 PID,但无法被调度,并且)。
    后果:大量僵尸进程会导致 PID 耗尽,系统无法创建新进程。

  2. 同步父子进程
    父进程可能需要等待子进程完成特定任务后再继续执行(如数据处理、文件读写)。

  3. 获取子进程退出状态
    父进程需知道子进程是正常退出(如返回码)、被信号终止,还是其他异常情况。【这里可以通过系统调用来获取不同的值来表示不同的情况,在wait和waitpid接口中存在参数status(输出型参数,由操作系统填充,如果传递NULL,表示不关心子进程的退出状态信息。),status在系统中以整形的方式存在,但不同区间的比特位代表不同的信息(如下图)】

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

进程之间具有独立性,因此父进程获取子进程运行状态不能简单地通过访问某个全局变量获取子进程状态因为父进程无法看到该变量(每个进程有自己的独立的进程地址空间),只能通过操作系统调用接口来实现。

关于status参数,它是一个整型指针,用来存储子进程的退出状态。status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位),表示含义为:
如果进程正常退出,那么高八位为进程的退出状态码;如果进程被信号所杀(异常中止),那么低七位表示信号码,第八位表示core dump标志核心转储,是操作系统在程序异常终止时生成的一个文件,记录了程序崩溃时的内存状态、寄存器值、堆栈信息等关键数据。
在这里插入图片描述

exitCode = (status >> 8) & 0xFF; //退出码
exitSignal = status & 0x7F;      //退出信号//or 使用系统定义的宏正常退出:
WIFEXITED(status):若为真,表示子进程正常退出。
WEXITSTATUS(status):获取子进程的退出码(即exit(code)中的code)。信号终止:
WIFSIGNALED(status):若为真,表示子进程被信号终止。
WTERMSIG(status):获取导致终止的信号编号(如SIGKILL对应9)。

总的来说,系统为什么要进行进程等待:

  • 僵尸进程无法被kill -9信号杀死(无法杀掉一个已经死掉的进程)杀死,需要通过进程等待来杀掉进程。
  • 需要通过进程等待获得子进程的退出情况(退出码)

3.2 进程等待的两个系统调用接口

3.2.1 wait()

wait函数的作用是让父进程等待子进程结束。调用wait的时候,父进程会被阻塞,直到有一个子进程结束。然后wait会返回结束的子进程的PID,并且通过参数status来传递子进程的退出状态。

#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);//返回值:成功返回被等待进程pid,失败返回-1。
参数:输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

如果有多个子进程,父进程每次调用wait只能处理一个,所以可能需要循环调用直到所有子进程都被回收,否则可能会有僵尸进程残留。

3.2.2 waitpid()

waitpid函数更灵活。它的参数中可以指定要等待的子进程的PID,或者用-1表示等待任意子进程,类似wait。另外,waitpid还可以设置选项,比如WNOHANG,这样父进程不会被阻塞,可以立即返回检查是否有子进程结束。这在需要父进程同时处理其他任务的时候很有用,避免阻塞。

pid_ t waitpid(pid_t pid, int *status, int options);
//返回值:当正常返回的时候waitpid返回收集到的子进程的进程ID;如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
//参数:pid:Pid=-1,等待任一个子进程。与wait等效。Pid>0.等待其进程ID与pid相等的子进程。status:WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)options:WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。

区别

那wait和waitpid的区别主要在哪儿呢?

参数waitwaitpid
指定进程❌ 只能等任意✅ 可指定PID
阻塞控制❌ 强制等待✅ 支持非阻塞
状态获取✅ 基础信息✅ 详细信息

如果子进程永远在执行,父进程wait会一直在等待子进程退出,在等待期间,父进程不能做任何事情,这种等待叫做阻塞等待 (回忆阻塞状态,scanf会等待硬件资源,这个例子是等待软件资源)

除了可以指定PID和选项之外,waitpid可以更精确地控制要等待哪个子进程,以及是否阻塞。比如,当父进程有多个子进程时,如果使用wait,只能按任意顺序处理结束的子进程,而waitpid可以选择等待特定的子进程,或者以非阻塞方式轮询WNOHANG子进程状态。

举个例子,假设父进程创建了三个子进程,然后想要等待第二个子进程结束,这时候就可以用waitpid,传入第二个子进程的PID作为参数。或者,如果父进程不想阻塞,可以设置WNOHANG选项,这样如果没有子进程结束,waitpid会立即返回0,而不会让父进程挂起。

那如何正确使用这些函数呢?

比如,父进程fork之后,子进程可能执行不同的任务,父进程需要收集它们的退出状态。用wait的话,父进程会阻塞直到有子进程结束,然后处理。而用waitpid的话,可以更灵活,比如循环调用waitpid(-1, &status, WNOHANG)来非阻塞地收集所有已结束的子进程,避免僵尸进程的产生,同时父进程可以做其他事情。

关于非阻塞轮询方式需要注意:
非阻塞轮询方式WNOHANG,可以做自己的事情

  1. 父进程顺带做自己事情的时候,这个任务不能太重,因为等待子进程退出信息才是主要任务
  2. 若子进程先于父进程任务退出,那么等待一会儿再回收也是可以的,并不是立即需要回收子进程。
  3. 通过进程等待,可以保证父进程是最后一个退出的进程,这意味着父进程创建的所有子进程已被回收。
//wait
int status;
pid_t pid = fork();
if (pid == 0) {// 子进程执行任务后退出//while(1){}   若子进程不退出,那么父进程wait阻塞等待exit(42);
} else {wait(&status);  // 父进程阻塞等待子进程结束if (WIFEXITED(status)) {printf("子进程退出码: %d\n", WEXITSTATUS(status));  // 输出42}
}//waitpid
int status;
pid_t child_pid = fork();
if (child_pid == 0) {// 子进程任务//while(1){} 可以通过WNOHANG触发非阻塞轮询方式exit(3);
} else {// 父进程非阻塞等待特定子进程while (waitpid(child_pid, &status, WNOHANG) == 0) {printf("子进程未结束,父进程继续工作...\n");sleep(1);}if (WIFEXITED(status)) {printf("子进程退出码: %d\n", WEXITSTATUS(status));  // 输出3}
}

四、进程程序替换

进程程序替换是Linux系统中一个重要的概念,它允许一个进程用另一个程序完全替换当前的执行内容,同时保留进程的基本属性(如PID、文件描述符等)。这一过程通过exec系列函数实现,这些函数能够加载新的程序映像到当前进程中,从而改变进程的行为。调用exec并不创建新进程,所以调用exec前后该进程的pid并未改变。

4.1 进程替换原理(单进程)

之前了解到一个进程执行的过程是,首先系统创建该进程的PCB并分配进程地址空间(虚拟内存),创建映射物理内存的页表。进程先将存储在磁盘上的代码块和数据块加载至物理内存后开始执行,运行到execl函数处,由于ls指令也是存放在磁盘上的,进程替换就非常简单地用ls指令的代码块和数据块替换掉进程的代码块和数据块,再将进程从ls指令的main函数重新执行,就达到了进程切换的目的。

int main()
{printf("before\n");execl("/usr/bin/ls","ls","-a",NULL);printf("after\n");//无法执行after,因为已被替换return 0;
}

4.2 多进程版程序替换效果——验证程序替换接口

int main()
{pid_t id = fork();if(id == 0){// 子进程执行进程替换//sleep(5)printf("before: i am a process,pid: %d, ppid: %d\n",getpid(),getppid());// 要执行的程序 、 怎样执行该程序 、 ...为可变参数列表execl("/usr/bin/ls","ls","-a","-l",NULL);//这类方法的标准写法//execl("/usr/bin/top","top",NULL);//execv("usr/bin/ls",myargv);//execl("./otherExec","otherExec",NULL);printf("after: i am a process,pid: %d, ppid: %d\n",getpid(),getppid());exit(0);//防止子进程继续运行后续代码}//父进程pid_t ret = waitpid(id,NULL,0);if(ret > 0){printf("等待子进程返回成功,father pid: %d, ret id: %d\n",getpid(),ret);}sleep(5);return 0;
}

在这里插入图片描述
现象:程序打印before,等待五秒后切换ls进程执行,ls执行完毕瞬间waitpid接收到子进程退出信号,遂执行父进程下的打印操作,等待五秒后程序退出。

我们知道父子进程是独立的两块进程地址空间,且存在写时拷贝技术,所以子进程在替换进程的时候,是不会影响到父进程的。

写时拷贝在修改数据时生效,替换了ls的数据块可以理解,但代码块存放在常量区按理来说不应该会被修改,所以不应该发生写时拷贝,但代码块不发生写时拷贝,岂不是就会影响到父进程的执行?
答:系统层面上写时拷贝不仅发生在数据区,也发生在代码区,用户无法修改代码区的数据,但操作系统需要写入ls代码至父子进程,由于这块代码区是父子共享的且只读,所以仍然发生了写时拷贝。

程序替换有没有创建新的进程?
很明显是没有,这一点在 ps ajx指令可以看到,并没有额外的进程被创建,只是修改了原PCB等结构体的一些字段。但系统是如何做到替换呢?
exec系统调用的步骤是:加载新程序到内存,替换原有代码段和数据段,调整堆栈,重置PC等寄存器,最后跳转到新程序的入口点(main)。
从进程地址空间角度来看,每个进程由用户地址空间与内核空间构成,在替换时,会保留内核结构,之是将新程序的代码和数据加载到当前进程的用户地址空间(直接覆盖),这一操作只需通过改变文件描述符表就可以做到替换,不创建新的进程是因为内核在执行替换时是复用了原本的内核数据结构(PCB信息),并且只是更改映射关系,重新创建进程开销巨大,这也就是exec与fork函数的区别之一。

CPU如何知道程序的入口地址?
Linux系统下,在编译时会产生一个程序头表,该表中存放着可执行文件的代码段和数据段的加载位置,在执行进程替换后,程序头表也会被替换,但同时,程序计数器PC的值也会被重置头表的入口地址,根据偏移量,PC就能够找到新程序的入口地址了。

多进程替换的特点

  • 替换后,进程的用户空间代码和数据被完全替换,新程序从其main函数开始执行。
  • 进程的PID保持不变,但代码段、数据段、堆和栈会被替换。
  • 替换成功后,原进程的后续代码不会执行,只有在替换失败时才会继续执行

4.3 进程替换的接口

//库函数 man 3int execl(const char *path, const char *arg, ...);//路径+参数列表,参数逐个传递,以NULL结尾int execlp(const char *file, const char *arg, ...);//文件名+参数列表,自动在PATH中查找int execle(const char *path, const char *arg, ...,char *const envp[]);//可自定义环境变量(通过envp数组传递)int execv(const char *path, char *const argv[]);//路径+参数数组,参数通过数组传递int execvp(const char *file, char *const argv[]);//文件名+参数数组,自动在PATH环境变量中查找可执行文件

exec系列函数:本质是一个加载器

环境变量是什么时候给进程的?
环境变量也是数据,创建子进程的时候环境变量就已经被子进程继承下去了(进程地址空间有一部分为进程环境变量),于是即使不写main函数中的环境变量参数表,系统也会找到进程的环境变量,替换进程后,环境变量不变。
子进程可以新增自己的环境变量信息(putenv),再往后的子进程可以继承它的环境变量。传递自定义环境变量列表时,原环境变量会被替换。

//系统调用接口
//以上六个库函数接口实现都会调用这一接口int execve(const char *path, char *const argv[], char *const envp[])

总结

本文篇幅较大,设计知识点众多,所以有几个点并没有深入讨论,如核心转储、exel接口函数中的环境变量表如何使用等,这些内容会在后续学习中逐渐补全。

👍 ​感谢各位大佬观看。如果本文有帮助,请点赞收藏支持~

相关文章:

【Linux】进程控制:创建、终止、等待与替换全解析

文章目录 前言一、重谈进程创建二、进程终止2.1 正常终止的退出码机制2.2 异常终止的信号机制2.3 进程常见的退出方法 三、进程等待&#xff1a;避免僵尸进程的关键3.1 进程等待的必要性3.2 进程等待的两个系统调用接口3.2.1 wait()3.2.2 waitpid()区别 四、进程程序替换4.1 进…...

LabVIEW 图像处理中常见的边缘检测算法

在 LabVIEW 图像处理领域&#xff0c;边缘检测对于提取图像特征、目标识别及图像分割等任务至关重要。以下介绍几种常见的边缘检测算法及其在 LabVIEW 中的应用。​ 一、Sobel 算子​ Sobel 算子是一种离散的一阶差分算子&#xff0c;用于计算图像灰度的近似梯度。它通过分别…...

Redis-场景缓存+秒杀+管道+消息队列

缓存一致性 1.两次更新 先更新数据库&#xff0c;再更新缓存&#xff1b;先更新缓存&#xff0c;再更新数据库&#xff1b; 出现不一致问题场景&#xff1a; 先更新数据库&#xff0c;再更新缓存&#xff1b; 先更新缓存&#xff0c;再更新数据库&#xff1b; 两次更新的适…...

亲身体验 Copilot Pages:利用人工智能实时整理和优化笔记

想象一下&#xff0c;有一款与云端相连的笔记本&#xff0c;它不仅能保存您收集的信息&#xff0c;还能自动整理&#xff0c;并根据需要添加详细信息和研究资料。这就是微软在华盛顿州雷德蒙德举行的 50 周年庆典活动上推出的全新 Copilot Pages 功能。这是微软在该活动中介绍的…...

[250409] GitHub Copilot 全面升级,推出AI代理模式,可支援MCP | Devin 2.0 发布

目录 GitHub Copilot 全面升级&#xff0c;推出AI代理模式&#xff0c;可支援MCPDevin 2.0 正式发布&#xff1a;带来全新的 AI 协作开发体验 GitHub Copilot 全面升级&#xff0c;推出AI代理模式&#xff0c;可支援MCP GitHub Copilot 迎来了一次重大升级&#xff0c;核心在于…...

代码随想录算法训练营Day25

一、力扣93.复原IP地址【medium】 题目链接&#xff1a;力扣93.复原IP地址 left x300 视频链接&#xff1a;代码随想录 1、思路 时间复杂度&#xff1a; O ( n ) O(n) O(n) 2、代码 class Solution:def restoreIpAddresses(self, s: str) -> List[str]:n len(s)ans []…...

支持企业知识库和联网搜索,360AI企业知识库驱动业务深度融合

在企业智能化转型进程中&#xff0c;高效整合内外部结构化与非结构化数据资源、快速构建AI能力已成为制胜未来的核心命题。360 DeepSeek企业知识库助力企业实现知识管理、辅助决策与业务场景落地的全链路贯通&#xff0c;重塑智能化升级路径。 1 企业知识库构建 终结信息孤岛…...

2025年R2 移动式压力容器充装证精选多选题练习

R2 移动式压力容器充装证精选多选题练习&#xff1a; 1、《特种设备安全法》规定&#xff0c;特种设备使用单位应当建立特种设备安全技术档案。安全技术档案应当包括以下内容&#xff1a;&#xff08; &#xff09; A. 特种设备的定期检验和定期自行检查记录 B. 特种设备的日…...

掌握Django内联TabularInline和StackedInline示例

掌握Django内联TabularInline和StackedInline示例 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 掌握Django内联TabularInline和StackedInline示例**前提条件****Django 内联管理简…...

ABAP+CS

平时开发中如果遇到某个字段等于A或B或C很多时的枚举条件很多时&#xff0c;平时我们都是写 if BUKRS A OR BUKRS B OR BUKRS C. ENDIF. 可以替换为CS&#xff0c;更加简洁&#xff0c;如下&#xff0c;要记得加空格 IF A B C D CS BUKRS. ENDIF....

python reportlab模块----操作PDF文件

reportlab模块----操作PDF文件 一. 安装模块二. reportlab相关介绍三. 扩展canvas类四. 水平写入完整代码五. 垂直写入完整代码 一. 安装模块 pip install reportlab二. reportlab相关介绍 # 1. letter 生成A4纸张尺寸 from reportlab.lib.pagesizes import letter print(let…...

javascript里用代理做链式调用。

JavaScript 的 Proxy 对象来实现一种动态的链式调用&#xff0c;最终完成加法操作。我们来逐步分析代码的逻辑&#xff1a; 1. createProxy 函数 function createProxy(value 0) {const valueGetter () > value;return new Proxy({}, {get(target, prop) {if (prop Sym…...

SpringBoot将HTML转化成PDF文件

准备好相关字体文件&#xff08;如果HTML内含有中文&#xff0c;避免乱码&#xff09;。我这边用的是谷歌免费的中文字体&#xff0c;源于&#xff1a;Gitee 极速下载/noto-cjk - Gitee.com&#xff08;在此表示感谢&#xff09;准备好一个HTML文件&#xff08;HTML标签记得封好…...

Elasticsearch 集群搭建

一、集群规划 1.1 节点角色规划 节点类型配置要求推荐数量Master节点低磁盘、中等CPU/内存3&#xff08;奇数防止脑裂&#xff09;Data节点高磁盘、高内存、多核CPU根据数据量扩展Coordinating节点高CPU/内存、低磁盘2&#xff08;可选&#xff09; 1.2 硬件建议 内存&…...

BGP路由协议之对等体

IGP 可以通过组播报文发现直连链路上的邻居&#xff0c;而 BGP 是通过 TCP&#xff1a;179 来实现的。BGP 需要手工的方式去配置邻居。不需要直连&#xff0c;只要路由能通就可以建立邻居 IBGP 与 EBGP IBGP :(Internal BGP) :位于相同自治系统的 BGP 路由器之间的 BGP 邻接关…...

H3C的MSTP+VRRP高可靠性组网技术(MSTP单域)

以下内容纯为博主分享自己的想法和理解&#xff0c;如有错误轻喷 MSTP多生成树协议可以基于不同实例实现不同VLAN之间的负载分担 VRRP虚拟路由器冗余协议可以提高网关的可靠性防止单点故障的可能 在以前这两种协议通常一起搭配组网&#xff0c;来提高网络的可靠性和稳定性&a…...

oracle 动态性能视图

Oracle 数据库中的 V$SQLAREA 是一个动态性能视图&#xff08;Dynamic Performance View&#xff09;&#xff0c;用于记录共享池&#xff08;Shared Pool&#xff09;中所有 SQL 语句的统计信息。每个 SQL 语句在共享池中存储为一个游标&#xff08;Cursor&#xff09;&#x…...

chrome extension开发框架WXT之WXT Storage api解析【补充说明一】

在 defineItem 方法里&#xff0c;fallback、init、version 和 migrations 这些参数能够让你对存储项进行更为细致的设置&#xff0c;像设定默认值、初始化值、版本控制以及数据迁移等操作。下面详细说明这些参数的使用方法&#xff1a; fallback 参数 fallback 参数为 getVa…...

浦江晨曦曲:科技与自然共舞的未来诗篇

故事背景 故事发生在未来上海&#xff0c;这座国际大都市通过尖端科技与生态自然的完美融合&#xff0c;重新定义了人类与环境的共生关系。从黄浦江畔的智慧能源矩阵到云端漂浮的烘焙工坊&#xff0c;每个场景都诉说着科技赋能下的人文温度。 故事摘要 当晨曦染红黄浦江面&…...

Lua 函数使用的完整指南

在 Lua 中&#xff0c;函数是一等公民&#xff08;First-Class Citizen&#xff09;&#xff0c;这意味着函数可以像其他值一样被赋值、传递和操作。以下是 Lua 函数定义的完整指南&#xff0c;涵盖基础语法、高级特性、设计模式及性能优化。 在Lua 中&#xff0c;函数定义的完…...

算法进阶指南 袭击

题目描述 在与联盟的战斗中屡战屡败后&#xff0c;帝国撤退到了最后一个据点。依靠其强大的防御系统&#xff0c;帝国击退了联盟的六波猛烈进攻。 经过几天的苦思冥想&#xff0c;联盟将军亚瑟终于注意到帝国防御系统唯一的弱点就是能源供应。 该系统由 N 个核电站提供能源&…...

HTTPS为何仍有安全漏洞?解析加密协议下的攻击面

本文深度剖析HTTPS协议在传输层、证书体系、配置管理三个维度的安全盲区&#xff0c;揭示SSL/TLS加密掩盖下的11类攻击路径。基于Equifax、SolarWinds等重大事件的技术复盘&#xff0c;提供包含自动化证书巡检、动态协议升级、加密流量威胁检测的立体防御方案。 HTTPS不等于绝…...

行业案例 | SAS 基于 SQL 托管实例构建高弹性安全的数据平台

SAS是全球领先的数据与AI公司&#xff0c;专注于行业解决方案&#xff0c;帮助企业高效利用数据驱动决策。在本案例中&#xff0c;SAS通过采用Azure SQL托管实例&#xff0c;成功迁移和管理近1,000个数据库&#xff0c;减少运维负担&#xff0c;提升数据价值挖掘能力。这一方案…...

NO.82十六届蓝桥杯备战|动态规划-从记忆化搜索到动态规划|下楼梯|数字三角形(C++)

记忆化搜索 在搜索的过程中&#xff0c;如果搜索树中有很多重复的结点&#xff0c;此时可以通过⼀个"备忘录"&#xff0c;记录第⼀次搜索到的结果。当下⼀次搜索到这个结点时&#xff0c;直接在"备忘录"⾥⾯找结果。其中&#xff0c;搜索树中的⼀个⼀个结点…...

工业制造各个系统术语

简单总结下 文章目录 MES:制造执行系统ERP:企业资源计划PLM:产品生命周期管理MRP:物资需求计划QMS:质量管理系统APS:高级计划与排程SRM:供应商关系管理SCM:供应链管理CRM:客户关系管理WMS:仓库管理系统TMS:运输管理系统PMS:生产管理系统LES:物流执行系统FICO:财务与成本控制模块…...

搜广推校招面经七十一

滴滴算法工程师面经 一、矩阵分解的原理与优化意义 矩阵分解在推荐系统中是一个非常核心的方法&#xff0c;尤其是在 协同过滤(Collaborative Filtering) 中。我们可以通过用户对物品的评分行为来推测用户的喜好&#xff0c;从而推荐他们可能喜欢的内容。 1.1. 直观理解&…...

解决 ECharts 图表无数据显示问题

问题&#xff1a; 在开发项目时&#xff0c;后端明明已经成功返回了数据&#xff0c;但在展示手账发布数量趋势和树洞帖子发布数量趋势的 ECharts 图表中&#xff0c;却只有坐标轴&#xff0c;没有任何数据显示。 以我的VUE项目开发可视化面板为例&#xff0c;下面将详细分析可…...

【UE5】RTS游戏的框选功能实现

目录 效果 步骤 一、项目准备 二、框选NPC并移动到指定地点 三、框选效果 效果 步骤 一、项目准备 1. 新建一个俯视角游戏工程 2. 新建一个pawn、玩家控制器和游戏模式&#xff0c;这里分别命名为“MyPawn”、“MyController”和“MyGameMode” 3. 打开“MyGameMode”…...

【同步教程】基于Apache SeaTunnel从MySQL同步到MySQL——Demo方舟计划

文章作者&#xff1a;陈飞 中付支付大数据工程师 大家好&#xff0c;很高兴通过 SeaTunnel Demo 方舟计划 和大家分享一个 简单但常见的 MySQL 到 MySQL 数据同步与合并场景案例。 我是陈飞&#xff0c;目前就职于中付支付基础架构部&#xff0c;从事大数据相关工作&#xff…...

人工智能与认知科学的交汇:机器是否能“理解”?

📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:AI与认知的“悖论” 当我们谈论人工智能时,往往聚焦于它的“能力”——会下围棋、会写文章、会画画,甚至能写代码。这些能力让AI像极了一个“聪明人”。但一个根本问题始终没有被真正解…...

React Native 0.79发布 - 更快的工具及更多改进

React Native 0.79版本发布了。 此版本在多个方面进行了性能改进&#xff0c;并修复了一些漏洞。首先&#xff0c;得益于延迟哈希技术&#xff0c;Metro的启动速度变快了&#xff0c;并且对包导出提供了稳定支持。由于JS包压缩方式的改变等原因&#xff0c;Android的启动时间也…...

嵌入式---灰度传感器

灰度传感器概览 一、定义与核心功能 1. 定义 灰度传感器是一种基于 光反射原理 的光电传感器&#xff0c;通过检测物体表面对入射光&#xff08;多为红外光或可见光&#xff09;的反射强度&#xff0c;将光信号转换为电信号&#xff0c;从而判断目标物体的 灰度值&#xff0…...

基于ueditor编辑器的功能开发之增加自定义一键排版功能

用户有自己的文章格式&#xff0c;要求复制或者粘贴进来的文章能够一键排版&#xff0c;不需要手动调试 这个需求的话咱们就需要自己去注册一个事件啦&#xff0c;这里我没有修改源码&#xff0c;而是在编辑器初始化之后给他注册了一个事件 我的工具列表变量 vue组件中data中…...

docker部署elk

一、准备镜像 二、创建Elasticsearch容器 2.1启动Elasticsearch容器 docker run -d --name elasticsearch \-e "discovery.typesingle-node" \-e "bootstrap.memory_locktrue" \-e "ES_JAVA_OPTS-Xms2g -Xmx2g" \-e "xpack.security.enab…...

BGP路由协议

为方便管理规模不断扩大的网络&#xff0c;网络被分成了不同的 AS (Autonomous System&#xff0c;自治系统)。早期&#xff0c;EGP (Exterior Gateway Protocol&#xff0c;外部网关协议)被用于实现在 AS 之间动态交换路由信息。但是 EGP 设计得比较简单&#xff0c;只发布网络…...

vue3中watch的使用示例

使用情况说明&#xff1a; 1、父组件中有个表格&#xff0c;点击表格行的修改基础信息&#xff0c;弹出修改对话框&#xff1b; 2、修改内容点击确认&#xff0c;发送请求&#xff0c;后端更新数据&#xff1b;不修改内容不发送请求&#xff1b; 3、可以连续修改&#xff1b…...

OpenBMC:BmcWeb 处理http请求7 完成http请求

OpenBMC:BmcWeb 处理http请求6 调用路由处理函数-CSDN博客 用户会通过填充asyncResp设置响应内容 OpenBMC:BmcWeb 处理http请求1 生成Request和AsyncResp对象_bmc web-CSDN博客 构造了asyncResp 可以看到asyncResp是一个shared_ptr 并且在构造后设置了setCompleteRequestHand…...

pair与tuple

pair pair是 C STL&#xff08;标准模板库&#xff09;中的一个模板类&#xff0c;用于表示一对相关的对象。它是一个简单的容器&#xff0c;存储两个数据项&#xff0c;它们可以是不同类型的。pair 常用于需要将两个元素一起操作的情况&#xff0c;例如在处理字典&#xff08…...

RecyclerView 和 ListView从 设计理念、性能优化 和 扩展能力 三个维度展开分析

一、RecyclerView 的核心定义&#xff08;设计理念&#xff09; RecyclerView 是 Android Jetpack 中的高级滚动容器&#xff0c;用于展示大数据集&#xff0c;其核心特性包括&#xff1a; 模块化设计&#xff1a;分离布局管理&#xff08;LayoutManager&#xff09;、动画&am…...

望远镜自动调焦怎样利用直线轴承结构?

以下是对望远镜调焦结构相关内容的分析&#xff1a; 调焦结构基本构成与原理 驱动部分&#xff1a;采用步进电机驱动滚珠丝杠&#xff0c;步进电机能够精确控制转动角度和步数&#xff0c;从而精确控制滚珠丝杠的转动&#xff0c;为调焦提供动力来源。 传动部分&#xff1a;…...

C++学习之服务器EPOLL模型、处理客户端请求、向客户端回复数、向客户端发送文件

目录 1.启动epoll模型 2.和客户端建立新连接 3.接受客户端Http请求数据 4.代码回顾从接受的数据中读出请求行 5.请求行解析 6.正则表达式以及匹配 7.解析请求行以及后续处理 8.对path处理说明 9.如何回复响应数据 10.对文件对应content-type如何查询 11.服务器处理流…...

Explain的使用

1.使用explain语句去查看分析结果 如explain select * from test1 where id=1;会出现:id selecttype table type possible_keys key key_len ref rows extra各列。 其中, type=const表示通过索引一次就找到了; key=primary的话,表示使用了主键; type=all,表示为全表…...

DDoS防御与流量优化

实训背景 某在线游戏平台遭受频繁DDoS攻击&#xff0c;需部署Linux网关实现以下防护与优化功能&#xff1a; 防御SYN洪水攻击&#xff1a;自动识别并拦截高频SYN请求。连接数限制&#xff1a;限制单个IP的最大并发连接数为100&#xff0c;防止资源耗尽。流量优先级保障&#…...

文件上传漏洞原理学习

什么是文件上传漏洞 文件上传漏洞是指用户上传了一个可执行的脚本文件&#xff0c;并通过此脚本文件获得了执行服务器端命令的能力。“文件上传” 本身没有问题&#xff0c;有问题的是文件上传后&#xff0c;服务器怎么处理、解释文件。如果服务器的处理逻辑做的不够安全&#…...

005.Gitlab CICD变量使用

文章目录 变量介绍预定义变量项目信息类版本控制类流水线执行类runner环境类作业执行类容器注册类其他类别 自定义变量 变量使用预定义变量使用创建流水线提交流水作业 自定义变量使用创建流水线提交流水作业 图形UI创建变量UI自定义变量创建流水线提交流水作业 变量介绍 预定…...

即时通讯软件BeeWorks,企业如何实现细粒度的权限控制?

BeeWorks作为一款专为企业设计的即时通讯平台&#xff0c;高度重视用户隐私安全&#xff0c;采取了多种措施来保障数据的保密性、完整性和可用性。 首先&#xff0c;BeeWorks采用私有化部署模式&#xff0c;企业可以将服务器架设在自己的网络环境中&#xff0c;所有通讯数据&a…...

高可用架构:Keepalived、Nginx与Docker深度解析

本文深入解析了Keepalived技术&#xff0c;阐述其基于VRRP协议实现高可用的核心功能&#xff0c;包括虚拟路由器冗余、健康检查、负载均衡集成及脚本执行与通知。同时&#xff0c;设计了Nginx高可用方案&#xff0c;涵盖双机主从、主主及多点集群模式&#xff0c;分析其优缺点。…...

127.0.0.1本地环回地址(Loopback Address)

127.0.0.1 是计算机网络中的一个特殊IPv4地址&#xff0c;称为本地环回地址&#xff08;Loopback Address&#xff09;&#xff0c;主要用于以下用途&#xff1a; 1. 基本定义 本地主机&#xff08;Localhost&#xff09;&#xff1a;该地址始终指向当前正在使用的计算机本身&a…...

Windows Terminal 美化增强攻略 2.0:打造个性化高效开发环境(快捷键介绍、编程语言环境、starship美化、高效命令行工具)

前言&#xff1a;从 1.0 到 2.0&#xff0c;终端美化进阶之旅 去年&#xff0c;我曾在文章《使用 oh-my-posh 和 clink 打造个性化 PowerShell 和 CMD》中分享了 Windows 终端的美化方案。那时&#xff0c;我选择了 oh-my-posh 作为核心工具&#xff0c;虽然效果不错&#xff…...

网络出故障时,四大表(MAC表、ARP表、路由表、转发表)怎么查?看看这套排查顺序

网络出故障时&#xff0c;四大表 (MAC表、ARP表、路由表、转发表) 怎么查 说正题之前&#xff0c;我们先来假设一个场景&#xff1a; 场景假设&#xff1a; 一台华为设备突然上不了网&#xff0c;或者访问某个 IP 不通。 你会怎么排查&#xff1f; 别慌&#xff0c;兄弟&a…...