【linux-进程2】进程控制
🌈环境变量
🍄初识
系统带的命令可以直接运行(ls ll命令等),但是我们自己写的命令必须要带上路径才能运行(./myproc),这是什么原因导致的?如果我们也想自己写的命令直接运行不带路径怎么搞? ----接下来揭晓答案
用ll明了直接显示处理三个文件。但是要运行我们自己创建的文件就要带上目录:这些就和环境变量有关。
- 看环境变量内容:
echo $PATH //显示操作系统搜索可执行文件的路径
- 可以看到环境变量PATH当中有多条路径,这些路径由冒号隔开,当你使用ls命令时,系统就会查看环境变量PATH,然后默认从左到右依次在各个路径当中进行查找。
- 像上面的ls命令啥的都在环境变量中储存了相应路径。
🐴设置自己的环境变量
这里我们也可以将自己写的命令设置成环境变量,一般有两种做法,这里我只推荐一种。
将我们的命令复制到环境变量下:
- pwd查看变量路径
- 将路径复制到环境变量路径set PATH=$PATH+复制的路径
- echo $PATH,如果目录上没有就把2命令的set换成export再来一遍就行了。
🐴常见的环境变量:
PATH:用于指定系统中可执行文件的路径,当你在命令行中输入一个命令时,系统会在 PATH 变量指定的路径中查找该命令的可执行文件。
HOME:用于指定当前用户的主目录路径。
USER:用于指定当前用户名。
SHELL:用于指定当前用户所使用的 Shell 程序路径。
🐴对于 Linux 操作系统,下面是一些常用的环境变量命令:
env
:显示当前所有环境变量。export var=value
:设置一个环境变量。echo $var
:显示一个环境变量的值。echo $PATH
:显示当前的 PATH 环境变量设置。export PATH=$PATH:new_path
:在 PATH 环境变量中添加一个新的路径。clear
:清除屏幕上的输出。exit
:关闭当前的终端窗口。
🍄环境变量对进程的作用
环境变量对进程的作用非常重要,因为它们提供了进程可以访问的信息和资源,包括但不限于以下内容:
系统配置信息:例如PATH环境变量包含了可执行文件的路径列表,进程可以通过访问该变量来查找和执行命令。
用户信息:例如HOME环境变量包含了当前用户的家目录路径,进程可以通过访问该变量来获取用户的工作目录。
语言和区域设置:例如LANG环境变量包含了当前系统的语言设置,进程可以通过访问该变量来确定如何显示和处理文本数据。
总之,环境变量是进程与操作系统之间进行通信和协作的一种重要方式。它们为进程提供了必要的信息和资源,使得进程能够正常运行和完成任务。
🌈程序地址空间
程序地址空间指的是一个进程在运行时所使用的虚拟内存空间。在现代操作系统中,每个进程都被分配了一个独立的虚拟地址空间,该空间包含了程序的代码、数据、堆栈等部分。
- 程序地址空间通常被分为以下几个部分:
-
代码段(text segment):包含程序的机器指令,通常是只读的。
-
数据段(data segment):包含程序中已经被初始化的全局变量和静态变量。
-
BSS段(bss segment):包含程序中未被初始化的全局变量和静态变量,其值通常为0。
-
堆(heap):包含由程序在运行时动态分配的内存,通常是由调用malloc等函数分配的。
-
栈(stack):包含函数调用时的局部变量、函数参数以及函数返回地址等信息。
程序地址空间在虚拟内存中,需要由操作系统管理,操作系统为每个进程分配一段独立的虚拟地址空间,并映射到物理内存中,以便程序能够访问所需的内存。操作系统还提供了一些系统调用,使得进程可以动态地请求更多的内存,或者释放已经不需要的内存。
在这个代码中,变量a是第一个被定义的,因此它被分配了最高的地址。变量b是第二个被定义的,因此它被分配在a的下方。同样,变量c是第三个被定义的,因此它被分配在b的下方。因此,这些变量在栈上的地址大小应该是按照以下顺序分配的:
- 变量a:最高的地址,地址值最大。(栈底)
- 变量b:次高的地址,地址值稍小于a的地址。
- 变量c:最低的地址,地址值最小。(栈顶)
这个栈是倒着放的,不是我们固定思维的正放。
接下来再看一个代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>int un_g_val; //未初始化全局变量int g_val = 100; //初始化全局变量int main(int argc, char *argv[]){printf("text: %p\n", main);printf("uninit: %p\n", &un_g_val);printf("init: %p\n", &g_val);char* p = (char*)malloc(16); printf("heap: % p\n", p); //堆printf("stack:%p\n", &p); //栈return 0;}
这个代码就验证了上面地址的情况,注意!我写的未初始化全局区和已初始化全局区的顺序错了,所以地址才不是连续增大的。
- 接下来我们 我们看一段代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{pid_t id = fork();if(id < 0){perror("fork");return 0;}else if(id == 0){ //child,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取g_val=100;printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);}else{ //parentsleep(3);printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);}sleep(1);return 0;
}
两者输入的内容不一样,但是地址确实一样的那说明啥?他们肯定不是存在物理内存上。如果存的物理地址一样,那这个地址存的内容必定一样。就比如从学校回家。今天可以做1路汽车在少年宫下,然后转2路到家。你也可以坐66路公交到天涯海角栈在坐666路到家。所以他们一定不是存在物理内存。而是存在虚拟地址上
👿进程地址空间不是物理地址
铁汁们,进程地址空间不是实际上的物理地址,而是虚拟的地址。所以原来我们在C语言学的地址空间也不是真正意义上的物理地址。
- 进程地址空间通常是虚拟地址空间,而不是物理地址空间。在操作系统中,每个进程都有自己的地址空间,其中包含该进程的代码、数据和堆栈等。这个地址空间是虚拟的,因为它只是一个进程视为自己的地址空间,而不是实际的物理地址空间。
- 当进程在执行时,它的虚拟地址需要被映射到实际的物理地址。这个映射由操作系统内核中的内存管理单元(MMU)完成,它将进程的虚拟地址转换为对应的物理地址。这个转换是透明的,因此进程可以像它正在访问实际物理内存一样访问它的虚拟地址空间。
- 总之,进程的地址空间是虚拟地址空间,需要通过内存管理单元将其映射到物理地址空间才能在实际的硬件上执行。
- 以前学的地址都不是物理地址全部都是虚拟地址。
🍄进程地址空间
每一个进程在创建后操作系统就会给他配置一个虚拟地址用来存放这个进程的内容。进程地址空间的本质也是内核的一种数据结构和PCB相似。在Linux当中进程地址空间具体由结构体mm_struct实现。进程地址空间就类似于一把尺子,尺子的刻度由0x00000000到0xffffffff,尺子按照刻度被划分为各个区域,例如代码区、堆区、栈区等。而在结构体mm_struct当中,便记录了各个边界刻度,例如代码区的开始刻度与结束刻度,如下图所示:
而想把进程地址空间和物理空间进行联系起来需要用到一个介质页表(也是一种数据结构)虚拟地址通过页表的映射存储到物理内存的不同地方。到这里,肯定有很多疑问,别急,我们来一一讲解。
👿为什么不是直接存到物理地址
内存管理的需要:操作系统需要对内存进行管理,包括内存的分配、释放、保护和共享等。如果让进程直接存在物理内存,就会给内存管理带来很大的困难,而虚拟地址空间可以方便地进行内存管理。
多道程序设计的需要:现代操作系统通常支持多道程序设计,这意味着多个进程可以同时运行在计算机上。如果让进程直接存在物理内存,就会导致不同进程之间的内存冲突和资源竞争,从而影响系统的正常运行。
内存保护的需要:操作系统需要保护系统的内存不被未经授权的进程访问和破坏。如果让进程直接存在物理内存,就很难进行内存保护,而虚拟地址空间可以为每个进程分配独立的地址空间,从而实现内存保护。
内存利用率的需要:直接存到物理内存会导致物理内存的使用不充分,出现碎片化现象。
👿给进程虚拟地址空间的好处
提高内存利用率:虚拟地址空间允许多个进程共享同一块物理内存,从而提高内存利用率。当一个进程需要更多的内存时,操作系统可以动态地为其分配更多的虚拟地址空间,而不必实际增加物理内存的大小。
实现内存保护:虚拟地址空间可以为每个进程分配单独的地址空间,从而防止进程相互干扰或破坏。操作系统可以利用内存保护机制来确保每个进程只能访问其分配的虚拟地址空间,从而保护系统的安全性和稳定性。
支持多道程序设计:虚拟地址空间支持多道程序设计,使得多个进程可以在同一时间运行。每个进程都可以拥有自己的地址空间,从而避免了不同进程之间的地址冲突和资源竞争,确保了系统的正常运行。
支持动态链接库:虚拟地址空间还可以支持动态链接库,这使得多个进程可以共享同一份库文件,从而减少了内存使用和磁盘空间的占用。
便于内存管理:虚拟地址空间的使用使得操作系统可以更方便地进行内存管理。
👿虚拟地址空间和物理内存的链接
虚拟地址要想和物理内存联系起来就需要一种内核数据结构----页表。
为什么会有页表?
- 如果这个进程是错误的,那它的虚拟地址写到物理内存上后操作系统无法正确读取这个信息,相当于浪费了很多不必要的空间。
- 其次进程这么多,这个虚拟地址映射到这里,那个映射到那里。如果我们像运行这个进程,那咋去找到它?所以操作系统需要记录下每一个进程存在的位置。
所以进程的作用:
内存管理:页表可以将虚拟地址空间划分为固定大小的页,每个页对应着一段连续的物理内存区域。这样一来,多个进程可以共享同一块物理内存,而不需要每个进程都分配独立的物理内存空间。
虚拟化:页表实现了虚拟内存的概念,使得进程可以在自己的虚拟地址空间中执行,而不需要考虑物理内存的具体细节。这样一来,操作系统可以更加灵活地管理内存资源,从而提高系统的整体性能和稳定性。
动态分配:当一个进程需要更多的内存时,操作系统可以动态地为其分配新的虚拟地址空间,并将其映射到物理内存上,而不需要为其分配新的物理内存空间。反之,当一个进程不再需要某个虚拟地址空间时,操作系统可以将其对应的物理内存释放,并将虚拟地址空间与物理内存之间的映射关系删除,以便于更好地利用内存资源。
内存保护:页表还可以提供一些额外的保护和安全特性,如权限控制、内存保护等。例如,操作系统可以将某些页面标记为只读,从而防止程序对其进行写入操作,保护系统的稳定性和安全性。
🍄写时拷贝
我们再回到上面那个奇怪的代码:为啥父子进程的物理内存一样,但是内容却不一样?
这里就用到了一门新技术:写时拷贝
- 写时拷贝(Copy-On-Write,COW)是一种优化技术,用于优化在进程复制时涉及的内存使用。在写时拷贝技术中,操作系统在内存中为子进程创建一个共享原始内存区域的虚拟副本,而不是创建一个完整的父进程物理副本。
- 写时拷贝技术的主要优点是可以避免在进程复制时产生额外的物理内存开销。因为新进程与原始进程共享相同的物理内存页面,所以只有在其中一个进程需要修改这些页面时,才会产生额外的物理内存开销。
- 如果说无脑为子进程创建父进程的副本,那子进程的很多代码和数据用不到就会造成资源和空间的浪费。所以写时拷贝非常不错。
👿写时拷贝的优点
节省内存开销:写时拷贝技术可以在进程复制时避免不必要的物理内存开销。因为新进程与原始进程共享相同的物理内存页面,所以只有在其中一个进程需要修改这些页面时,才会产生额外的物理内存开销。
提高程序运行效率:写时拷贝技术可以提高程序的运行效率,因为它避免了不必要的物理内存拷贝。如果进程在复制时需要完全复制物理内存,那么进程复制的时间和开销将会很大。使用写时拷贝技术,操作系统只需要复制虚拟地址空间的页表条目,而不需要真正复制整个物理内存页面,因此可以节省很多时间和资源。
保护数据安全:写时拷贝技术可以保护原始数据的安全性。因为新进程与原始进程共享相同的物理内存页面,所以当一个进程对共享页面进行写操作时,它不会影响到原始进程的数据。这可以避免数据的意外修改和损坏。
支持共享内存:写时拷贝技术支持共享内存,使得多个进程可以共享同一块物理内存区域。如果没有写时拷贝技术,共享内存将会很困难,因为多个进程可能会同时修改同一块物理内存,导致数据的混乱和错误。而使用写时拷贝技术,多个进程可以共享相同的物理内存页面,并且只有在其中一个进程需要修改页面时才会发生复制,从而保证了共享内存的正确性和安全性。
所以我们再分析上面的代码:
- 刚开始父进程拷贝了一个子进程,然后父与子进程共享数据和代码。后面子进程的全局变量g_val修改,修改后的全局变量区映射到页表的其他地方,然后页表又映射到 物理内存的其他位置。所以才会出现地址相同,但是打印的结果不同。
- 这里通过写时拷贝把修改后的子进程虚拟地址给页表。而不是子进程完全复制一份父进程。
- 物理地址肯定是发生改变的,那个不变的地址是虚拟地址,别搞混虚拟地址和物理地址。
注意:之所以页表映射有蓝色,有红色是因为不同内容要存在不同地方。全局变量存在已初始化全局区。函数等存在栈区等等,所以有蓝色,有红色 。
🌈进程终止
🍄进程退出的场景
- 代码运行完毕, 结果正确------皆大欢喜
- 代码运行完毕,结果错误------- 小小失落
- 代码异常终止------挠头抓耳
- 进程终止是指进程的运行被终止或者结束。进程终止可以是正常的结束,也可以是异常的终止。正常的结束通常是指进程完成了它的任务,或者根据某些条件主动地调用了系统调用来终止自己。在这种情况下,操作系统会释放进程所占用的资源,并将进程从系统中移除。
- 而异常的终止则是指进程在执行过程中出现了错误或者被强制终止。例如,进程访问了不存在的内存地址,或者收到了操作系统发出的信号来强制终止。在这种情况下,操作系统会立即中止进程的执行,并回收进程所占用的资源。
🍄进程退出码
echo $?
#include<stdio.h>
#include<stdlib.h>int main()
{printf("hello world!");return 0;
}
0就表示进程正常退出,如果是非0值代表的进程异常退出,并且这个值还代表这个进程所报错误。可以通过strerror来看错误码!
#include<stdio.h>
#include<string.h>int main()
{int i=0; //有的编译器不支持把i=0写道for里面for(i;i<150;i++){printf("%d:%s\n",i, strerror(i)); }return 0;
}
- 如果我们随便输入一个命令:
🍄进程正常退出
👿return退出
在函数中我们经常都是return 0 ,这个就告诉函数程序执行完要退出了。但是要想要想进程退出那就不能用它了。
👿exit/_exit退出
如果我们想让进程退出,那我们就要用到其他的函数exit, _exit。
exit函数
使用exit函数退出进程也是我们常用的方法,exit函数可以在代码中的任何地方退出进程,并且exit函数在退出进程前会做一系列工作:
- 执行用户通过atexit或on_exit定义的清理函数。
- 关闭所有打开的流,所有的缓存数据均被写入。
- 调用_exit函数终止进程。
这个细节就是在执行exit进行退出时编译器打印了上面的命令 I am a precess!.注意下面操作
_exit
这个不常用,相比exit,但是我们可以了解一下,_exit函数也可以在代码中的任何地方退出进程,但是_exit函数会直接终止进程,并不会在退出进程前会做任何收尾工作。
我们把前面的代码稍微修改一下即可:
👿return, exit, _exit区别
return
语句用于函数返回一个值,并将控制流程返回到调用该函数的地方。exit()
函数用于终止程序的运行并返回到操作系统,它会在退出之前执行所有必要的清理操作(例如关闭打开的文件、释放内存等)。在调用exit()
函数之前,程序可以正常地执行所有必要的操作,因此exit()
函数是安全的程序退出方式。_exit()
函数与exit()
函数类似,都用于终止程序的运行并返回到操作系统,但它会立即退出程序,不会执行任何清理操作,这可能会导致数据损坏或资源泄漏等问题。因此,除非必须要立即退出程序且不需要进行清理操作,否则应该使用exit()
函数。
🌈进程等待
🍄什么是?为啥有?
进程等待是指父进程在创建子进程后,通过调用
wait()
或waitpid()
等函数,等待子进程结束并获取子进程的退出状态。进程等待的主要目的是让父进程能够控制子进程的执行顺序,并在必要时对子进程进行处理。进程等待的必要性
- 获取子进程退出状态:进程等待还可以让父进程获取子进程的退出状态,这对于调试和排错非常有用。父进程可以根据子进程的退出状态来判断子进程是否正常退出,以及出错的原因。
- 控制子进程执行顺序:如果父进程需要等待多个子进程执行完毕后再进行后续操作,那么可以使用进程等待来控制子进程的执行顺序。父进程可以在需要等待的地方调用
wait()
或waitpid()
函数,以确保子进程已经执行完毕。- 避免子进程成为僵尸进程:如果父进程没有及时处理子进程的退出状态,那么子进程就会成为僵尸进程,占用系统资源并导致一些问题。通过进程等待,父进程可以及时处理子进程的退出状态,避免出现僵尸进程。
🍄进程等待的方法
👿wait等待
wait()是一个系统调用,用于等待子进程结束并获取子进程的退出状态。它的原型如下:
#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);
- wait() 函数的返回值是子进程的进程号,如果出错则返回 -1。
- 如果父进程没有子进程,那么 wait() 函数会立即返回。
wait()
函数的参数status
是一个整型指针,用于存储子进程的退出状态。如果子进程正常结束,它的退出状态会被存储在status
中,父进程可以通过WIFEXITED(status)
和WEXITSTATUS(status)
宏来获取子进程的退出状态。如果子进程异常结束,例如被信号终止,那么status
中存储的是一个描述异常结束原因的信号值。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{pid_t id = fork();if(id == 0){//childint count = 10;while(count--){printf("I am child...PID:%d, PPID:%d\n", getpid(), getppid());sleep(1);}exit(0);}//fatherint status = 0;pid_t ret = wait(&status);if(ret > 0){//wait successprintf("wait child success...\n");if(WIFEXITED(status)){//exit normalprintf("exit code:%d\n", WEXITSTATUS(status));}}sleep(3);return 0;
}
我们用这个脚本:
while :; do ps axj | head -1 && ps axj | grep proc | grep -v grep;echo "######################";sleep 1;done
👿waitpid等待
waitpid
是一个系统调用函数,它用于等待指定进程的状态改变,例如进程终止或暂停等。waitpid允许父进程等待它的一个子进程的状态改变,而不必阻塞整个进程。这使得父进程能够同时等待多个子进程的状态改变。
- 函数原型:
pid_t waitpid(pid_t pid, int *status, int options);
pid
参数指定要等待的进程的进程ID,如果指定为-1
,则等待任何子进程。status
参数是一个整数指针,用于存储子进程的退出状态或其他信息。options
参数用于指定等待的进程状态,如WNOHANG
选项表示在没有状态改变的情况下立即返回,而不是阻塞等待状态改变。当
waitpid
成功时,返回终止或暂停进程的进程ID,如果没有进程处于指定状态,则返回0。如果出错,则返回-1。请注意,
waitpid
只能等待子进程的状态改变,如果要等待其他进程的状态改变,可以使用其他函数,如wait
和waitid
。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{pid_t id = fork();if (id == 0){//child int count = 10;while (count--){printf("I am child...PID:%d, PPID:%d\n", getpid(), getppid());sleep(1);}exit(0);}//father int status = 0;pid_t ret = waitpid(id, &status, 0);if (ret >= 0){//wait success printf("wait child success...\n");if (WIFEXITED(status)){//exit normal printf("exit code:%d\n", WEXITSTATUS(status));}else{//signal killed printf("killed by siganl %d\n", status & 0x7F);}}sleep(3);return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{pid_t id = fork();if (id == 0){int count = 10;while (count--){printf("I am child...PID:%d, PPID:%d\n", getpid(), getppid());sleep(1);}exit(0);}int status = 0;pid_t ret = waitpid(id, &status, 0);if (ret >= 0){printf("wait child success...\n");if (WIFEXITED(status)){printf("exit code:%d\n", WEXITSTATUS(status));}else{printf("killed by siganl %d\n", status & 0x7F);}}sleep(3);return 0;
}
在父进程运行过程中,我们可以尝试使用kill -9命令将子进程杀死,这时父进程也能等待子进程成功。 但是被信号杀死而退出的进程,其退出码将没有意义。
🍄获取子进程status
- wait, waitpid函数都有status,status存的是进程的状态。
- 如果传递NULL,表示不关心子进程的退出状态信息。
- 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
- status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):
在status的低16比特位当中,高8位表示进程的退出状态,即退出码。进程若是被信号所杀,则低7位表示终止信号,而第8位比特位是core dump标志。
如果我们想得到进程的退出码和退出信号就可以使用位运算:
exitCode = (status >> 8) & 0xFF; //退出码
exitSignal = status & 0x7F; //退出信号
对于此,系统当中提供了两个宏来获取退出码和退出信号。
- WIFEXITED(status):用于查看进程是否是正常退出,本质是检查是否收到信号。
- WEXITSTATUS(status):用于获取进程的退出码。
exitNormal = WIFEXITED(status); //是否正常退出
exitCode = WEXITSTATUS(status); //获取退出码
需要注意的是,当一个进程非正常退出时,说明该进程是被信号所杀,那么该进程的退出码也就没有意义了。
👿wait和waitpid的区别:
- wait函数会等待任何子进程结束并获取其退出状态,而waitpid函数只会等待指定的子进程结束并获取其退出状态。
- wait函数没有提供获取子进程终止原因的选项,而waitpid函数可以通过指定选项来获取子进程的终止原因(例如,被信号终止还是正常退出)。
waitpid函数的原型为:
pid_t waitpid(pid_t pid, int *status, int options);
其中,pid参数指定要等待的子进程的PID。如果pid为-1,则等待任何子进程结束。status参数用于存储子进程的退出状态。options参数可以指定等待子进程的行为,例如是否阻塞等待、是否只等待被特定信号中断的子进程等等。
wait函数的原型为:
pid_t wait(int *status);
其中,status参数用于存储子进程的退出状态。
- 如果没有子进程在运行,wait函数会阻塞程序,直到有子进程结束为止,而waitpid函数可以通过指定WNOHANG选项来避免阻塞。
- 如果子进程已经结束,wait函数和waitpid函数都会立即返回,且获取到子进程的退出状态。如果子进程尚未结束,wait函数和waitpid函数都会等待子进程结束并获取其退出状态。
- 在多进程程序中,waitpid函数可以通过指定pid参数来等待特定的子进程结束。如果不指定pid参数或pid为-1,则等待任何子进程结束。
- 在使用这些函数时,需要注意避免出现僵尸进程,即已经结束但父进程尚未调用wait或waitpid来获取退出状态的子进程。可以使用信号处理函数或者使用waitpid函数中的WNOHANG选项来避免出现僵尸进程。
相关文章:

【linux-进程2】进程控制
🌈环境变量 🍄初识 系统带的命令可以直接运行(ls ll命令等),但是我们自己写的命令必须要带上路径才能运行(./myproc),这是什么原因导致的?如果我们也想自己写的命令直接…...

【五一创作】多域名环境和Office 365混合部署方案
目录 一、多域名环境是什么? 二、Office 365是什么? 三、多域名环境与Office 365的结合 总结 一、多域名环境是什么? 多域名环境指的是一个企业拥有多个域名,这些域名可能隶属于不同的子公司、部门或者品牌,但是都归属于同一个母公司。例如,一个中国电信集团旗下有…...

Vue:路由route
一、概念 1、组成 每一个路由都由 key 和 value 组成。 keyvalue路由 route。 2、本质 路由的本质:一个路由表达了一组对应关系。路由器的本质:管理多组对应关系。 3、路由的工作原理 点击之后路径变化——>路由器监视到变化——>根据路径…...

Windows系统被faust勒索病毒攻击勒索病毒解密服务器与数据库解密恢复
在近期,一种名为faust后缀的勒索病毒威胁已经引起了全球计算机系统安全领域的关注。faust勒索病毒是一种基于RSA加密算法的恶意软件,能够加密目标计算机系统上的所有文件,并向用户勒索赎金来承诺解密恢复操作。下面为大家介绍一下Windows系统…...

Java面试题总结 | Java面试题总结7- Redis模块(持续更新)
Redis 文章目录 Redisredis的线程模型Redis的Mysql的区别Redis和传统的关系型数据库有什么不同?Redis常见的数据结构zset数据结构Redis中rehash过程redis为什么不考虑线程安全的问题呢Redis单线程为什么还能这么快?为什么Redis是单线程的?red…...

虹科案例 | 如何通过智能、非接触式测量解决方案,提高起重机的安全和效率?
PART 1 案例详情 自建造初期以来,起重机行业已经走了很长一段路。技术的使用在行业进步中发挥了重要作用,降低了使用桥式起重机的危险性。特别是,智能、非接触式测量解决方案通过使用高架升降机更安全、更高效、更高效,为行业的进…...

流程图拖拽视觉编程-流程编辑器
目录 一、简介 二、流程编辑器-视图实现 三、参考资料 一、简介 前期文章: 流程图拖拽视觉编程--概述_Jason~shen的博客-CSDN博客 本期内容: 本期将介绍流程编辑器模块的实现方法,效果图如下所示。该模块基于QT Graphics/View实现&…...

6.hashcode与equals区别与联系
1.hashCode介绍 hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。 这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。 2.equals介…...

智能家居“落地者”:三翼鸟用场景方案持续链接大众消费
互联网分析沙龙(techxue)原创 作者 | 锡海 编辑 | 七喜 从上海车展再到AWE2023展会,只要有大型活动的地方,都能看到人潮汹涌的景象,久违的烟火气又回来了。数据显示,社会消费已出现较为强劲反弹࿰…...

【MATLAB图像处理实用案例详解(12)】——利用BP神经网络实现图像压缩
目录 一、图像压缩二、BP神经网络实现图像压缩原理三、算法步骤3.1 图像块划分3.2 归一化3.3 建立BP神经网络3.4 保存结果 四、效果演示 一、图像压缩 常见的文件压缩软件如WinZip、WinRAR等采用的是无损压缩,能够完全恢复原文件内容。多媒体信息具有信息量大、冗余…...

java学习之枚举
目录 一、枚举引出 二、分析问题 三、 解决方案-枚举 四、枚举的二种实现方式 五、应用案例 六、小结 一、枚举引出 package enum_;public class Enumeration01 {public static void main(String[] args) {Season spring new Season("春天", "温暖")…...

IPsec中IKE与ISAKMP过程分析(主模式-消息2)
IPsec中IKE与ISAKMP过程分析(主模式-消息1)_搞搞搞高傲的博客-CSDN博客 IPsec协议族中IKE(Internet Key Exchange)是一种基于ISAKMP的协议,它为建立IPSec安全通信隧道提供了一种无痕密钥交换的机制。简单来说ÿ…...

KDZR-10A三相直流电阻测试仪
一、产品概述 直流电阻的测量仪是变压器、互感器、电抗器、电磁操作机构等感性线圈制造中半成品、成品出厂试验、安装、交接试验及电力部门预防性试验的项目,能有效发现感性线圈的选材、焊接、连接部位松动、缺股、断线等制造缺陷和运行后存在的隐患。 为了满足感…...

C语言入门篇——指针篇
目录 1、指针 1.1内存地址 1.2基地址 1.3指针变量 2、指针类型 2.1指针-整数 2.2指针的解引用 3、特殊指针 3.1野指针 3.2空指针 4、指针运算 4.1指针-指针 4.2指针的关系运算 5、指针和数组 6、二级指针 7、指针数组 1、指针 1.1内存地址 内存是电脑上特别重…...

Python小姿势 - Python学习笔记:如何使用Python创建一个简单的计算器
Python学习笔记:如何使用Python创建一个简单的计算器 在本教程中,我们将学习如何使用Python创建一个简单的计算器。我们将学习如何使用Python的内置函数input()和print(),以及如何使用Python的运算符来完成这个项目。 首先,让我们…...

庖丁解牛 - FLAME: Taming Backdoors in Federated Learning
文章目录 论文笔记 - FLAME: Taming Backdoors in Federated Learning1. 基本信息2. 研究动机3. 基本原理3.1 面临挑战分析3.2 FLAME 算法总体概述3.3 FLAME 算法设计思想3.3.1 Dynamic Model Filtering3.3.2 Adaptive Clipping3.3.3 Adaptive Noising4. 结论论文笔记 - FLAME:…...

C++设计模式20:状态模式
C++ 23种设计模式系列文章目录 创建型模式 第1式 工厂方法模式 第2式 抽象工厂模式 第3式 单例模式 第4式 建造者模式 第5式 原型模式 结构型模式 第6式 适配器模式 第7式 桥接模式 第8式 组合模式 第9式 装饰器模式...

Embarcadero Delphi 11 和 C++Builder 11 免费社区版发布!
Embarcadero为Delphi和CBuilder的最新11.3版本提供了社区版许可证。这是Delphi或CBuilder的免费版本,适用于学生,业余爱好者和初创公司(因为许可证仅对于收入有限的公司或个人)。 什么是CE社区版? Delphi 和 CBuilde…...

JSP+Struct+MySql基于BBS管理系统设计与实现(源代码+论文+中英资料+开题报告+答辩PPT)
现今的社会是一个信息飞速发达的社会,其中在信息的交流当中,互联网占据着一个非常重要的位置。人们可以通过在互联网上收到最新的消息,也可以通过互联网进行信息的交流。而论坛就是大家进行信息交流的其中一个渠道。 论坛的概念:论…...

800字带你弄懂Http请求和响应
Hello ,我是小索奇,今天给大家分享一下计算机网络中的请求和响应,这些在javaWeb中也是必不可少的哈 HTTP介绍 HTTP是一种用于在Web应用程序之间传递数据的协议,HTTP请求和响应是客户端与服务器之间进行通信的基本单位。我们可以用一个生活中…...

【Java笔试强训 6】
🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、选择题 二、编程题 🔥不要二 …...

2023年最新5A景区有多少个?Python可视化告诉你
2023年最新5A景区有多少个?Python可视化告诉你 五一小长假来了,很多人想抓住小长假的机会去旅游。 5A景区是大多数人的首选,全国最新有多少个5A景区呢,应该还有很多人不知道。本文用Python进行可视化,告诉你答案。 …...

C++中的list容器
文章目录 list的介绍list的使用list的构造list iterator的使用list capacitylist元素访问list modifierslist的迭代器失效 list与vector的对比 list的介绍 list是可以在常数范围内的任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代; …...

Apache Hudi初探(二)(与spark的结合)
背景 目前hudi的与spark的集合还是基于spark datasource V1来的,这一点可以查看hudi的source实现就可以知道: class DefaultSource extends RelationProviderwith SchemaRelationProviderwith CreatableRelationProviderwith DataSourceRegisterwith StreamSinkPr…...

颠覆世界的“数字孪生”到底是什么?这篇文章带你搞懂全部内涵!
在春节很火的电影《流浪地球2》中,已经去世的小女孩图丫丫,被她的父亲重新将其个人的信息模型导入最强大的计算机而“复活”了。屏幕中的丫丫就是一个数字孪生体。我们可以看到她的一颦一笑,听到她跟你的对话,看到她做出反应。这就…...

Vector底层结构和源码分析
Vector的基本介绍 1.Vector类的定义说明 public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable 2)Vector底层也是一个对象数组,protected Objectl] elementData; 3)Vector是线程同步的&…...
计算卸载论文阅读01-理论梳理
标题:When Learning Joins Edge: Real-time Proportional Computation Offloading via Deep Reinforcement Learning 会议:ICPADS 2019 一、梳理 问题:在任务进行卸载时,往往忽略了任务的特定的卸载比例。 模型:针…...

Windows 11 本地 php 开发环境搭建:PHP + Apache + MySQL +VSCode 安装和环境配置
目录 前言1. PHP 的下载、安装和配置1.1 下载 php1.2 安装 php1.3 配置 php 系统变量1.4 配置 php.ini 2. Apache 的下载、安装和配置2.1 下载 Apache2.2 安装 Apache2.3 修改配置 Apache2.4 指定服务端口(非必须)2.5 配置系统变量2.6 安装服务2.7 Apach…...

15个使用率超高的Python库,下载量均过亿
今天给大家分享最近一年内PyPI上下载量最高的Python包。现在我们来看看这些包的作用,他们之间的关系,以及为什么如此流行。 1. Urllib3:8.93亿次下载 Urllib3 是 Python 的 HTTP 客户端,它提供了许多 Python 标准库没有的功能。 …...

所有知识付费都可以用 ChatGPT 再割一次?
伴随春天一起到来的,还有如雨后春笋般冒出的 ChatGPT / AI 相关的付费社群、课程训练营、知识星球等。 ChatGPT 吹来的这股 AI 热潮,这几个月想必大家多多少少都能感受到。 ▲ 图片来源:网络 这两张图是最近在圈子里看到的。 一张是国内各…...