【Linux】玩转操作系统,深入刨析进程状态与调度机制

目录

  • 1. 进程排队
  • 2. 进程状态的表述
    • 2.1. 进程状态
    • 2.2 运行状态
    • 2.3. 阻塞状态
    • 2.4. 挂起状态
  • 3. Linux下具体的进程状态
    • 3.1. 运行状态R
    • 3.2. 可中断睡眠状态S
    • 3.3. 不可中断睡眠状态D
    • 3.4. 停止状态T
    • 3.5. 死亡状态X
    • 3.6. 僵尸状态Z
  • 4. 孤儿进程
  • 5. 优先级
  • 6. Linux的调度与切换
    • 6.1. 四个概念
    • 6.2. 进程切换
    • 6.3. 进程调度

1. 进程排队

  1. 进程排队:指的是操作系统将等待资源的进程组织成队列,以便按照特定的调度策略来决定哪个进程可以获取资源并继续执行,即:将进程放入到等待资源的队列中进行排队。

进程排队,表示进程不是一直在运行的,是在等待某种软硬件"资源"。eg:scanf,等待键盘资源。

即使进程被调度到CPU上执行,它也不会一直运行下去。在多任务操作系统中,进程的执行是分时的,每个进程会分配到一定的时间片来执行,当时间片用完,操作系统会暂停运行当前进程。

  1. 进程排队,一定是进程的task_struct(PCB)进行排队。

  2. 进程的task_struct(PCB)可以放入到多种数据结构中。

进程的PCB既可以被放入到全局的双链表中,又可以被放入到特定的队列中。当进程被放入到全局的双链表中,OS会在进程的每个PCB中创建链表节点的对象;当进程被放入到特定的队列中,OS会在队列的数据结构中创建或复用双链表节点,在PCB中设置队列节点的链接。

image.png

2. 进程状态的表述

前言:教材中描述进程状态的模型和实际操作系统(如:Linux)中实现的进程状态模型可能会有差异。

2.1. 进程状态

  1. 进程状态:本质是一个整形类型的变量,它定义在task_struct结构体中,用来描述进程的不同的不同状态。
  2. 进程状态,决定着进程的后续操作和它在操作系统的行为。

image.png

2.2 运行状态

运行状态:进程已经准备好随时被调度。即:正在CPU上执行以及在运行队列中等待被调度的进程。

💡Tips:一个CPU一个运行队列。
屏幕截图 2024-07-20 104921.png

2.3. 阻塞状态

阻塞状态:进程暂时无法继续执行,在等待某种软硬件"资源"。

💡Tips:每个硬件都有自己的队列!

  1. 当进程在等待软硬件资源的时候,资源没有就绪,操作系统就会先将进程的task_struct设置为阻塞状态、再将task_struct链入到等待资源的等待队列中。

  2. 状态的变迁,引起的是PCB会被操作系统变迁到不同的队列中!
    image.png

  3. 硬件的就绪状态,本质是硬件的资源准备好执行任务的状态,操作系统作为硬件的管理者,负责监控和管理这些硬件资源的状态。

硬件资源就绪,对于键盘的输入,通常是指键盘的中断机制已触发,表明有新的输入数据已经准备好了。

键盘的输入处理流程如下:硬件资源就绪(键盘输入准备完毕)→ OS通过驱动程序将数据从外设(键盘)搬到内存(内核输入缓冲区)→ 用户程序通过系统调用接口(scanf)将数据从内存搬到用户空间。

2.4. 挂起状态

挂起状态:进程被暂时停止执行,它的状态被保存,以便在将来某个时刻恢复。分为内部挂起、外部挂起。

  1. 外部挂起:也称为阻塞挂起。当系统资源紧张,如:内存空间不足,OS会将进程的代码和数据保存到磁盘的swap分区,以释放内存供其他进程使用,此时进程状态为挂起状态。当内存资源变的可用时,OS会将对应的代码和数据重新加载到内存中,并将其状态由挂起变为运行,以便它可以被调度执行。

  2. 唤出过程:当内存资源紧张时,OS会将内存中数据(等待资源的进程的代码和数据)交换到磁盘的swap分区中,以释放内存空间,这个过程称为唤出。

  3. 唤入过程:当需要恢复执行此进程时,就会将磁盘的swap分区保存的内容回到内存中,使进程可以继续执行,这个过程称为唤出。

image.png

问1:创建一个新进程,是先创建进程的PCB,还是先把进程的代码和数据加载到内存中?

答:先创建进程的PCB,再把进程的代码和数据加载到内存中,确保了OS对进程的创建和管理。

问2:磁盘的swap分区的大小是越大越好吗?

答:不是,会导致性能下降、资源浪费等问题。与内存相比,磁盘速度慢的多,如果swap分区很大,会导致OS过度依赖它,而频繁的唤入唤出操作会显著降低系统的性能,因为磁盘的IO速度远低于内存的读写速度。

  • swap分区不能设置过大,通常大小等于内存大小或内存大小的一半。

3. Linux下具体的进程状态

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

image.png

3.1. 运行状态R

运行状态R:进程正在运行或者准备运行。它可能正在CPU上执行,或者在运行队列中等待被调度。

在这里插入图片描述

  1. grep是单独指令,是程序,只有被运行,变成进程,它才会执行过滤操作,所以它的状态总是运行状态R。

  2. 前台进程(带+),可以被键盘(ctrl + c)终止;后台进程(不带+),不可以被键盘终止,可以通过发信号(kill -9 进程的PID),才可终止后台进程 ;前台进程 -> 后台进程:./程序 & 。

3.2. 可中断睡眠状态S

可中断睡眠S:也称为浅度睡眠或睡眠状态,意味着进程正在等待某个事件的完成,如: I/O操作、定时器到期(sleep函数)等,它可以被信号中断,如:ctrl + c、kill -9终止进程。

💡Tips:可中断睡眠睡眠S == 阻塞状态。

#include<stdio.h>
#include<unistd.h>int main()
{while(1){printf("I am a process, id: %d\n", getpid());sleep(1);}
}

在这里插入图片描述
问:为什么这个进程处于睡眠状态?

答:sleep函数会将进程由运行状态变为睡眠状态,等待指定的时间,进程会被OS唤醒。printf函数的执行速度通常是非常快的,因为CPU的执行速度很快,而printf是向显示器打印,需要访问外设,printf可能会等待I/O操作完成时使进程短暂的进入睡眠状态。

3.3. 不可中断睡眠状态D

不可中断睡眠D:也称为深度睡眠或磁盘休眠状态,它通常会等待硬件操作(如:磁盘I/O)完成,不能响应信号,直到它所等待的事件完成。

💡Tips:不可中断睡眠睡眠D == 阻塞状态。

eg:当一个进程发起磁盘的写入操作时,当内存资源十分吃紧,如果此进程处于睡眠状态S,OS就会将此进程杀掉,可能会导致数据丢失,所以此进程的状态被设置于不可中断睡眠状态D,OS不可以杀掉此进程,进程等待磁盘的结果以作出相应的应答。

3.4. 停止状态T

停止状态T:意味着进程已经被暂停或者正在被追踪,通常是因为接受到一个信号,或者是在调试器中被断点所拦截。

💡Tips:停止状态T == 阻塞状态。

  1. 可以通过发送SIGSTOP信号(kill -19)给进程来停止进程,通过发送SIGCONT信号(kill -18)让处于暂停状态的进程继续运行。

image.pngimage.png

3.5. 死亡状态X

死亡状态X:意味着进程已经终止,且资源已经被回收,它只是一个返回状态,不再存在于进程列表中。

3.6. 僵尸状态Z

僵尸状态:进程已经退出,但其父进程尚未调用wait( )来收集其退出信息。即: 进程是已退出但未清理的状态,等待父进程回收资源。

  1. 前提:子进程比父进程先退出。只要子进程退出了,父进程还在运行,但父进程没有读取子进程退出信息,子进程就进入Z状态,当父进程回收了子进程的资源,子进程由Z状态变为X状态。

处于僵尸状态的进程会一直保存在进程列表中。通常情况下,进程先变为Z状态,再变为X状态。

  1. 当一个Shell( bash )会话结束时,如果没有显示的调用wait( )回收子进程的资源,而Shell作为父进程,会自动调用wait( )来清理所有已经终止的子进程的资源,避免留下僵尸进程,后台进程除外。

  2. 当进程退出后,先会释放进程的代码和数据,进程的PCB不能被释放,因为它里面存储着结果数据,只有当父进程完成了资源的回收和状态的读取,PCB才会被释放。

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<wait.h> int main()
{pid_t id = fork();if(id < 0) return 1;else if(id == 0){//子进程int cnt = 5;while(cnt--){printf("I am child process, pid: %d, ppid:%d\n",getpid(    ),getppid()); sleep(1);}exit(0);}else{//父进程int cnt = 10;while(cnt--){printf("I am father process, pid: %d, ppid:%d\n",getpid    (),getppid());sleep(1);}}wait(NULL);printf("father wait child done...\n");sleep(5);
}
//现象:父子进程同时运行5s, 5s后子进程退出(变Z状态), 父进程在运行5s, 5s后父进程回收子进程资源(子进程由Z->X状态), 5s后父进程退出

a. 为什么要有僵尸状态Z?

  • 创建进程是希望这个进程执行特定任务,子进程在完成工作后,往往需要向父进程报告结果或者状态信息(子进程必须由结果数据保存在自己的PCB中) , 从而使父进程能够根据子进程的执行结果作出适当的响应。

b. 什么是僵尸状态Z?

  • 进程已经退出,但是当前进程的状态需要自己维持住,供父进程读取。

c. 如果父进程不读取子进程的退出数据呢?

  • 僵尸状态的进程会一直存在,而维护退出状态本质是用数据维护,存储在进程的PCB,所以task_struct对象也要一直存在,而数据结构对象本身就要占用内存,会造成内存泄漏。

4. 孤儿进程

孤儿进程:父进程比子进程先退出,子进程就称为"孤儿进程"。

  • 孤儿进程被PID为1的进程(操作系统)领养,由OS回收其资源。
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>int main()
{pid_t id = fork();if(id < 0) return 1;else if(id == 0){//子进程int cnt = 10;while(cnt--){printf("I am child process, pid: %d, ppid:%d\n",getpid(    ),getppid()); sleep(1);}exit(0);}else{//父进程int cnt = 5;while(cnt--){printf("I am father process, pid: %d, ppid:%d\n",getpid    (),getppid());sleep(1);}}                                                       
}

5. 优先级

优先级:CPU资源分配的先后顺序。

  1. 前提:进程要访问某种资源,进程通过一定的方式(排队),确认享受资源的先后顺序。

  2. 为什么要存在优先级?因为资源相对过少。

  3. 优先级本质是一个整数类型的变量,数值越小,优先级越高,具有优先执行的权力。

  4. 优先级PRI(new) = 优先级PRI(old) + nice。

Linux系统允许用户调整进程的优先级,但不能直接修改pri,而是修改进程的nice值。

nice值:是进程优先级的修正数据,!=进程优先级;优先级PRI(old)为默认优先级(值为80)。

  1. Linux优先级默认值为80,优先级的范围为[60 , 99],nice值的范围为[-20,19],一共40个。

Linux为什么调整优先级是要受限制的?

答:如果不受限制,则用户能够随意提高自己的进程优先级调整的非常高,那么很可能他们会过度提升自己的进程,使其始终处于高优先级的状态,导致常规进程难以得到CPU资源,产生进程饥饿现象。

💡Tips:任何分时系统(基于时间片进行轮转执行),确保了进程调度的公平性和系统的稳定性!

ps -l

  • 功能:显示当前登录用户的所有进程的信息。

XQO_I_HJQOJ~HJ{N96`XFI5.png
UID:代表执行者的身份、PID:进程的唯一标识符、PPID:子进程的父进程的唯一标识符、PRI:进程的优先级、NI:进程优先级的修正数据。

top -> r -> 输入进程的PID -> 输入nice值

  • 功能:用top命令更改已存在进程的nice值,从而调整进程的优先级。

优先级.gif

renice nice 进程的PID

  • 功能:更改已存在进程的nice值,从而调整进程的优先级。

6. Linux的调度与切换

6.1. 四个概念

现代操作系统可以分成不同类别,分时操作系统和实时操作系统是两种重要的类型。

对于分时OS,进程都是基于时间片进行轮转执行的。每个就绪进程在轮到自己时,将会获得一个时间片来执行,如果一个进程在时间片结束时还没有执行完,它就会立即被暂停,CPU将被分配给下个进程,造成多个进程在"同时"运行的假象。

对于实时OS,采用的是优先级驱动的调度策略,要求OS对用户有超高响应,其中一旦高优先级的进程一旦就绪,将立即抢占CPU执行,如:车载系统。

  1. 竞争性:系统中进程的数量多、而CPU资源少量,所以进程之间对于共享资源是具有竞争属性的。

  2. 独立性:多进程在运行期间互不影响。每个进程在执行时都有自己的私有执行环境,包括代码、数据等资源,它们各自独享自己的执行资源。

  3. 并行:多个进程在多个CPU下,分别同时进行运行。

  4. 并发:多个进程在一个CPU下采用进程切换的方式,在一段时间内,多个进程看起来同时执行。

6.2. 进程切换

进程切换 = 保护进程的硬件上下文 + 进程的硬件上下文恢复。是OS在多任务环境中实现进程间公平调度和并发执行的关键机制。

  1. 进程在运行的过程中,会产生大量的临时数据,小部分被存储在CPU的寄存器中,大部分被存储在内存中。

  2. 进程的硬件上下文:在某一时刻,CPU执行进程时,所有硬件状态信息的集合。如:CPU内部的寄存器中存储的所有临时数据等。

  3. 保存进程的硬件上下文:当一个进程的时间片结束、主动放弃CPU(等待某种资源scanf)、有更高优先级的进程就绪需要暂时停止执行,OS会保存该进程的硬件上下文到进程的PCB中。

  4. 进程的硬件上下文恢复:在保存完当前进程的上下文后,OS会选择下一个要运行的进程,如果该进程是第二次被调度,就会将该进程的PCB中上下文重新加载到CPU上,CPU会从上次的运行位置继续运行。

💡Tips:所有的保存都是为了最终的恢复,所有的恢复都是为了继续上次的运行位置继续执行。

  1. CPU中的寄存器从物理上是被所有进程共享,在任意时刻,CPU的寄存器由当前正在执行的进程独占使用,而寄存器内部保存的数据,是被该进程私有的。即:CPU中的寄存器只能有一套,寄存器内部保存的数据可以有多套。

💡Tips:寄存器 != 寄存器的内容。

6.3. 进程调度

在这里插入图片描述
背景:Linux的进程调度O(1)算法,需要考虑优先级、进程饥饿、以及效率等问题,这主要是通过是特定的数据结构和算法设计来实现的。

一、####数据结构

  1. queue[140]

这是个优先级数组(prio_array),它是一个长度为140的指针数组,每个元素包含一个链表头,该链表包含具有相同优先级的所有就绪进程,即:每个元素对应一个优先级队列,每个队列中的进程具有相同的优先级,它维护了140个优先级队列。

实时优先级:0~99,用于实时进程,以确保它们能够及时响应并完成任务。

普通优先级:100~139,通过nice值[-20,19]可以调整进程在该范围内的优先级,用于非实时进程,遵循时间片轮转调度策略,确保进程公平的共享CPU资源。image.png

  1. bitmap[5]

这是一个位图(prio_map),用于快速检测哪些优先级队列是非空的。它是一个5个整数的数组,每个整数有32个比特位,共有5*32=160个比特位 > 140,位图操作都是在比特级别进行的,时间复杂度为O(1),非常高效。

位图中的每个比特位的位置,对应着一个优先级队列;每个比特位的内容,表示这个队列是否为空。即:检测某个优先级队列中是否有进程,转为为检测对应比特位是否为1。

  1. nr_active

这是一个计数器,用于记录当前活跃进程队列中进程的总数。

struct q
{int nr_active;int bitmap[5];task_struct queue[140];
}

二、####算法实现

  1. 优先级

通过优先级数组和位图,调度器,可快速定位到最高优先级的非空队列。当需要调度下一个进程时,调度器首先会遍历位图,直到找到’第n位’为1才会停下,再访问queue数组中的下标值为’第n位’的元素,取出该队列中第一个进程进行运行。

  1. 避免进程饥饿

OS会将时间片耗尽的进程放到过期队列中,不让他们一直占用活跃队列的位置,确保其他进程被调度到CPU上执行;新增进程也会被加入到过期队列,不论这个新进程的优先级高低,避免了较高优先级的进程抢占CPU资源。而CPU只会执行活跃队列中的进程,当活跃队列上的进程都被执行完毕,两队列交换。

  1. 效率

因为bitmap[5]数组的存在,调度器只需要遍历bitmap[5]数组,而不是整个queue[140]数组,大大减少了遍历的次数。位图的查询操作时间复杂度为O(1),意味着无论多少个优先级队列,调度器只需要遍历bitmap[5],就可以快速找到非空优先级队列,大大提高了查找效率。

三、活跃进程队列、过期进程队列

  1. 活跃进程队列:包含了当前准备就绪,可以立即被执行的进程。

  2. 过期进程队列:包含了时间片耗尽,但未执行完毕的进程。

四、active指针、expired指针

  1. active指针永远指向活跃队列、expired指针永远指向过期队列。

  2. 进程的时间片一直存在,就会使活跃队列的进程一直在减少、过期队列的进程一直在增多。

struct q  
{int nr_active;int bitmap[5];task_struct queue[140];
}struct q array[2]; struct q* active = &array[0];    //活跃队列
struct q* expired = &array[1];  //过期队列swap(&active, &expired); //更改的只是指针变量的内容,队列内容并未改变

image.png

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

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

相关文章

在linux上面用drissionpage自动化遇到反爬?

目录 一、反爬内容1、案例12、案例2 二、后来发现的问题解决 一、反爬内容 1、案例1 反爬的响应文本返回如下&#xff1a;爬虫均能精准识别,测试链接:https://ziyuan.baidu.com/crawltools/index)非正常爬虫访问时:返回的压缩报文内容无法直接识别,可一定程度上保护站点信息安…

C语言进阶——一文带你深入了解“C语言关键字”(中篇)

本篇文章属于C语言进阶篇的“C语言关键字”&#xff0c;旨在分享我对C语言关键字的深度学习和了解。同时带领大家深入浅出的走进C语言进阶知识——关键字篇&#xff01; 目录 一、变量的命名规则 二、标识符的命名规则 一、变量的命名规则 1、命名应当直观且可以拼读&#x…

【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常

问题现象 BeetISQL中间件版本&#xff1a;2.13.8.RELEASE 客户在调用BeetISQL提供的api向yashandb的表中执行batch insert并将返回sequence设置到传入的java bean时&#xff0c;报如下异常&#xff1a; 问题的风险及影响 影响业务流程正常执行&#xff0c;无法获得batch ins…

史诗级动态分屏多画面PR开场视频模板MOGRT

Premiere Pro模板&#xff0c;创意史诗级动态分屏多画面开场视频模板mogrt 主要特点 全高清&#xff08;19201080&#xff09;分辨率 Pr2021或更高版本软件 非常易于定制 00:33秒持续时间 7个文本占位符 34个媒体占位符 https://prmuban.com/39328.html

【论文共读】【翻译】【GPT】Improving Language Understanding by Generative Pre-Training

GPT 原论文地址 翻译&#xff1a; Improving Language Understanding by Generative Pre-Training 通过生成式预训练提高语言理解能力 0. 摘要 自然语言理解包括各种不同的任务&#xff0c;例如文本蕴涵、问答、语义相似性评估和文档分类。尽管大量未标记的文本语料库很丰富…

基于 uPlot.js 的分段彩色条形图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 基于 uPlot.js 的分段彩色条形图 应用场景 分段彩色条形图广泛应用于数据可视化领域&#xff0c;用于展示数据的分布和趋势。它可以通过不同的颜色来表示数据的不同范围&#xff0c;帮助用户快速识别和理解数…

苹果手机微信拉黑了怎么恢复?简单3招,找回好友!

我们平时在使用微信和朋友交往的过程中&#xff0c;难免会产生一些摩擦&#xff0c;有时候我们可能因为一时冲动或误会而误将好友拉入黑名单。但当冷静下来&#xff0c;想要找回那份友谊时&#xff0c;该怎么办呢&#xff1f;别急&#xff0c;这里有3招简单又实用的方法&#x…

React间的组件通信

一、父传子&#xff08;props&#xff09; 步骤 父组件传递数据&#xff0c;子组件标签身上绑定属性子组件接收数据&#xff0c;props的参数 // 子组件 function Son(props) {return (<div>this is Son, {props.name}</div>) }// 父组件 function App() {const n…

WebGIS的地图渲染|SVG|Canvas|Canvas

说到地图&#xff0c;平时我们使用过百度地图、高德地图、腾讯地图等&#xff0c;如果涉及地图开发需求&#xff0c;也有很多选择&#xff0c;如前面提到的几个地图都会提供一套JS API&#xff0c;此外也有一些开源地图框架可以使用&#xff0c;如OpenLayers、Leaflet、Mapbox、…

EasyExcel 初使用—— Java 实现多种写入 Excel 功能

前言 大家好&#xff0c;我是雪荷。之前有一篇博客&#xff08;EasyExcel 初使用—— Java 实现读取 Excel 功能_java easyexcel.read-CSDN博客&#xff09;介绍了 Java 如何读取 Excel 表格&#xff0c;那么此篇博客就和大家介绍下 Java 如何利用 EasyExcel 写入 Excel。 Ea…

使用阿里云云主机通过nginx搭建文件服务器

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、准备基础环境二、安装配置nginx三、阿里云安全组配置安全组配置 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4ee96f38312e4771938e40f463987…

React Router-v6.25.1

以下例子是根据vitereactts构建的&#xff0c;使用路由前先安装好这些环境&#xff01;&#xff01;&#xff01;&#xff01; 1、路由的简单使用 首先要创建一个浏览器路由器并配置我们的第一个路由。这将为我们的 Web 应用启用客户端路由。 该main.jsx文件是入口点。打开它…

数字看板:跨行业需求下的创新与升级

在当今这个数据驱动的时代&#xff0c;数字看板作为信息展示与决策支持的重要工具&#xff0c;正逐步渗透到各行各业之中。从智慧城市到智能制造&#xff0c;从金融分析到医疗健康&#xff0c;数字看板以其直观、动态、高效的特点&#xff0c;成为了连接数据与决策者的桥梁。本…

Linux系列--shell编程一

一、Linux系统结构 一、内核层 内核是Linux系统的核心部分&#xff0c;它负责管理系统各种硬件设备、文件系统、内存管理和进程管理等核心任务。Linux内核设计了良好的模块化结构&#xff0c;可以动态地加载和卸载内核模块&#xff0c;这使得内核可以兼容各种不同的硬件设备和…

基于联咏 NT98692芯片赋能边缘计算IP摄像机与XVR监控系统解决方案

联咏 NT98692 是一款新世代整合度极高的 SoC&#xff0c;具有高影像品质、低位元率、低功耗&#xff0c;针对 8Kp30 边缘运算 IP 摄影机与后端监控系统 XVR 应用。此 SoC 整合了 ARM Quad Cortex A73 CPU 核心、新一代 ISP 和 AI ISP、H.265/H.264 视讯压缩编解码器、DSP、高效…

C++ primer plus 第16章string 类和标准模板库, 函数符概念

C primer plus 第16章string 类和标准模板库, 函数符概念 C primer plus 第16章string 类和标准模板库, 函数符概念 文章目录 C primer plus 第16章string 类和标准模板库, 函数符概念16.5.1 函数符概念程序清单16.15 functor.cpp 16.5.1 函数符概念 正如 STL定义了容器和迭代…

数据结构和算法入门

1.了解数据结构和算法 1.1 二分查找 二分查找&#xff08;Binary Search&#xff09;是一种在有序数组中查找特定元素的搜索算法。它的基本思想是将数组分成两半&#xff0c;然后比较目标值与中间元素的大小关系&#xff0c;从而确定应该在左半部分还是右半部分继续查找。这个…

基于 HTML+ECharts 实现智慧安防数据可视化大屏(含源码)

构建智慧安防数据可视化大屏&#xff1a;基于 HTML 和 ECharts 的实现 随着科技的不断进步&#xff0c;智慧安防系统已经成为保障公共安全的重要工具。通过数据可视化&#xff0c;安防管理人员可以实时监控关键区域的安全状况、人员流动以及设备状态&#xff0c;从而提高应急响…

XSS攻击与CSRF攻击

XSS攻击 XSS&#xff08;Cross Site Scripting&#xff0c;跨站脚本攻击&#xff09;&#xff0c;是指攻击者利用站点的漏洞&#xff0c;在表单提交时&#xff0c;在表单内容中加入一些恶意脚本&#xff0c;当其他正常用户浏览页面&#xff0c;而页面中刚好出现攻击者的恶意脚…

ffmpeg更改视频的帧率

note 视频帧率调整 帧率(fps-frame per second) 例如&#xff1a;原来帧率为30&#xff0c;调整后为1 现象&#xff1a;原来是每秒有30张图像&#xff0c;调整后每秒1张图像&#xff0c;看着图像很慢 实现&#xff1a;在每秒的时间区间里&#xff0c;取一张图像…