【嵌入式Linux】<总览> 多进程

文章目录

前言

一、进程的概念与结构

1. 相关概念

2. 内核区中的进程结构

3. 进程的状态

4. 获取进程ID函数

5. 进程组

6. 会话

二、进程创建

1. fork和vfork函数

2. 额外注意点

3. 构建进程链

4. 构建进程扇

三、进程终止

1. C程序的启动过程

2. 进程终止方式

四、特殊的进程

1. 僵尸进程

2. 守护进程

3. 孤儿进程

五、相关函数

1. wait函数

2. waitpid函数

3. execl函数

4. execlp函数

5. system函数


前言

在Linux中程序的运行涉及进程的相关知识,熟悉并掌握其相关知识在嵌入式Linux应用开发中至关重要。本篇记录进程的具体知识,若涉及版权问题,请联系本人删除!


一、进程的概念与结构

1. 相关概念

  • 程序:存放在硬盘的可执行文件。
  • 进程:是程序运行的实例,每个进程都有一个虚拟地址空间。进程之间相互独立,同时也存在相关机制来进行进程的通信。每个Linux进程都有唯一的进程ID(PID),其都是正整数。
  • 并发:虚假的同时运行多个进程,是单CPU切换速度极快的结果。
  • 并行:真实的同时运行多个进程,有多个CPU。
  • 命令:①如下图,通过命令"ps -aux"可以查看进程信息。②用kill -9可以强制退出进程。

2. 内核区中的进程结构

每启动一个进程,在虚拟地址空间的内核区中就会对应一个task_struct结构体(进程控制块PCB),如下图所示。其中包含了进程的ID、状态、优先级、调度策略、文件结构体指针(指向文件描述符表)等等。

3. 进程的状态

有五种常见状态:创建态、就绪态、运行态、阻塞态(挂起态)和退出态(终止态)。

  • 创建态:进程在创建时就是该状态,时间很短。
  • 就绪态:创建后就处于该状态,等待抢夺CPU时间片。
  • 运行态获得CPU资源使得该进程运行,当时间片用完后重新回到就绪态。
  • 阻塞态:进程强制放弃CPU,无法抢夺CPU时间片(例如sleep在休眠期间)。同时,阻塞态又分为不可中断和可中断类型。(执行中按下Ctrl+C能中断的是可中断类型)
  • 退出态:进程的终止,占用的系统资源被释放。(任何状态都可以直接转换为退出态)

僵尸状态:进程已经终止了,用户区资源已经被释放了,但是内核区中的task_struct仍有信息,ps的命令中STAT值为Z。

4. 获取进程ID函数

#include <unistd.h>
#include <sys/types.h>
当前进程ID: pid_t getpid(void);
当前进程的父进程ID: pid_t getppid(void);
当前进程的实际用户ID: uid_t getuid(void);
当前进程的有效用户ID: uid_t geteuid(void);
当前进程的用户组ID: gid_t getgid(void);
当前进程的进程组ID: pid_t getpgrp(void);
进程ID为pid的进程组ID: pid_t getpgid(pid_t pid);【注】实际用户是当前环境下的用户,有效用户是真正开启进程的用户

5. 进程组

【1】介绍:进程组就是多个进程的集合。每个进程组都有个组长,组长就是进程组中第一个进程。组长的PID等于进程组的ID。只有当进程组中的所有进程都退出或者转移了,这个进程组才会消失。

【2】创建进程组/转移进程到某个进程组:

int setpgid(pid_t pid, pid_t pgid);
//参数说明://pid表示进程的ID号//pgid表示进程组的ID号,若pgid不存在则创建进程组//返回值:成功返回0,失败返回-1

6. 会话

【1】介绍:会话(session)是由多个进程组所构成的。一个普通进程可以调用setsid函数使自己成为新会话的领头进程(会长),同时这个领头进程还会被放入到一个新的进程组中。

【2】相关函数:

#include <unistd.h>//获取进程所属的会话ID
pid_t getsid(pid_t pid);//将某个进程变成会话,得到守护进程
//哪个进程调用,哪个进程就会变成一个会话
pid_t setsid(void);

【3】注意事项:

  • 调用setsid函数不能是进程组的组长,如果是则调用失败。为了保证调用成功,可以调用fork函数创建子进程,然后终止父进程,让子进程来调用setsid函数。
  • 若调用的不是进程组的组长,那么调用会成功。当前进程就脱离了控制终端,因此不会阻塞终端。

二、进程创建

1. fork和vfork函数

【1】头文件:#include <sys/types.h>、#include <unistd.h>

【2】函数原型:①pid_t fork(void); ②pid_t vfork(void);

【3】功能:

  • fork创建子进程,且子进程复制父进程的内存空间。子、父进程谁先运行看进程调度。
  • vfork创建子进程,子进程先运行不复制父进程空间。

2. 额外注意点

  • fork和vfork被调用一次,会返回两次:子进程中的返回值为0,在父进程中的返回值则是子进程的PID。可以根据返回值不同来区分是父进程还是子进程。
  • 失败返回值:创建子进程失败会返回-1。
  • 执行位置:父进程是从main函数代码体首部开始执行,子进程是从fork函数之后开始执行。
  • 虚拟地址空间的用户空间:子进程中代码段与环境变量的物理空间和父进程是同一个。而其他的物理空间不是同一个(而是将父进程的复制一份给子进程),即使它们的虚拟地址是一样的。
  • 虚拟地址空间的内核空间:①子进程只复制父进程的文件描述符表,不复制但共享文件表项和inode。②父进程创建一个子进程后,文件表项中的引用计数器加1,当父进程close后计数器减1,子进程还是可以使用文件表项,只有当计数器为0时才会释放文件表项。

实验程序1:创建子进程,打印子、父进程中的pid信息。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(int argc, char **argv)
{//fork创建子进程,复制父进程空间pid_t pid = fork();//子、父进程中打印pidif (pid < 0) {perror("创建子进程失败");} else if (pid == 0) {//子进程printf("I am child process. PID: %d, PPID: %d, 返回的PID: %d\n", getpid(), getppid(), pid);} else {//父进程printf("I am parent process. PID: %d, PPID: %d, 返回的PID: %d\n", getpid(), getppid(), pid);}return 0;
}

实验程序2:父进程将文件指针定位到文件尾部,子进程写入内容。原有目录下有文件1.txt,原有内容为123

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char **argv)
{//命令行参数判定if (argc != 2) {printf("Command: %s <filename>\n", argv[0]);return -1;}//文件操作int fd = open(argv[1], O_WRONLY);if (fd < 0) {perror("文件打开错误");return -1;}//父进程改变文件指针到文件尾部//子进程等待父进程定位好后写入内容pid_t pid = fork();if (pid < 0) {perror("创建子进程错误");close(fd);return -1;} else if (pid > 0) {//父进程if (lseek(fd, 0, SEEK_END) < 0) {perror("文件指针定位错误");close(fd);return -1;}} else {//子进程sleep(2);//确保父进程先运行const char * content = "Hello, Can!\n";int contentSize = strlen(content);if (write(fd, content, contentSize) < contentSize) {printf("写入错误\n");close(fd);return -1;}}printf("--------pid: %d完成工作---------\n", getpid());//关闭文件:父子进程都会关闭,使得引用计数减为0close(fd);return 0;
}

3. 构建进程链

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(int argc, char **argv)
{//创建3个子进程,形成进程链for (int i = 0; i < 3; ++i) {pid_t pid = fork();if (pid < 0) {perror("创建失败");return -1;}if (pid > 0) { //若为父进程则退出break;}}printf("PID: %d, PPID: %d\n", getpid(), getppid());sleep(1);return 0;
}

4. 构建进程扇

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(int argc, char **argv)
{//创建3个子进程,形成进程扇for (int i = 0; i < 3; ++i) {pid_t pid = fork();if (pid < 0) {perror("创建失败");return -1;}if (pid == 0) {//若为子进程则退出break;}}printf("PID: %d, PPID: %d\n", getpid(), getppid());sleep(1);return 0;
}


 三、进程终止

1. C程序的启动过程

在main函数执行前,Linux内核会启动一个特殊例程,将命令行中的参数传给argc和argv。若主函数中有三个形参,那么该例程还会将环境信息构建成环境表传给第三个形参。最后,该例程还会登记进程的终止函数(进程终止前会调用)。

终止函数说明:

  • 每个进程都默认登记了一个标准的终止函数。
  • 终止函数在进程终止时释放一些资源。
  • 登记的多个终止函数的执行顺序按照的方式执行。
  • 用户自定义终止函数(无参无返回值),需要调用atexit函数向内核登记。

atexit函数:

【1】头文件:#include <stdlib.h>

【2】功能:向内核登记一个终止函数,该函数会在正常进程终止时被调用。

【3】函数原型:int atexit(void (*function)(void));

【4】返回值:成功返回0,否则返回非零值。

2. 进程终止方式

  • 正常终止:
    • ①main函数中return返回 会刷新标准IO缓存,会执行自定义的终止函数
    • ②调用库函数exit(0) 会刷新标准IO缓存,会执行自定义的终止函数
    • ③调用系统调用函数_exit(0)或_Exit(0) 不会刷新标准IO缓存,不会执行自定义的终止函数
    • ④最后一个线程从其启动例程返回
    • ⑤最后一个线程调用库函数pthread_exit
  • 异常终止:
    • ①调用库函数abort
    • ②接收到信号并终止(例如段错误会产生一个信号,然后终止进程)
    • ③最后一个线程对取消请求做处理响应

实验程序:运行下列代码,若参数指定为exit或return,文件中有写入的字符串,并且会执行自定义的终止函数;若参数指定为_exit,文件中没有任何内容,并且没有执行终止函数。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>//自定义终止函数
void fun1() {printf("Terminate: fun1\n");
}void fun2() {printf("Terminate: fun2\n");
}void fun3() {printf("Terminate: fun3\n");
}//主函数
int main(int argc, char **argv)
{//命令行参数判定if (argc != 3) {printf("commnd: %s <filename> <exit | return | _exit>\n", argv[0]);return -1;}//登记自定义终止函数atexit(fun1);atexit(fun2);atexit(fun3);//文件操作,忽视健壮性判定FILE *fd = fopen(argv[1], "w");//文件不存在则创建,调用失败返回NULLfprintf(fd, "Hello, world!\n");//向文件缓冲区写入字符串,若没有刷新或fclose则不会写入硬盘//根据参数选择退出方式if (!strcmp(argv[2], "exit")) {exit(0);} else if (!strcmp(argv[2], "return")) {return 0;} else {_exit(0);}
}


四、特殊的进程

1. 僵尸进程

  • 概念:子进程的虚拟地址空间中的用户区资源已经释放,但内核区中的task_struct没有被释放,那么该进程就是僵尸进程。
  • 释放僵尸进程的方式:
    • ①结束或kill僵尸进程的父进程,那么僵尸进程就会成为孤儿进程,然后会被init进程(1号进程)领养,最终会被回收。
    • ②让僵尸进程的父进程来回收。父进程每隔一段时间就查询子进程是否结束并回收,调用wait函数或waitpid函数,通过内核来释放僵尸进程。
    • ③采用信号SIGCHLD通知处理,在信号处理函数中调用wait函数。

程序示例:运行如下程序,就会生成僵尸进程。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(int argc, char **argv)
{//创建子进程pid_t pid = fork();if (pid < 0) {perror("创建子进程失败");return -1;}//子进程退出,成为僵尸进程if (pid == 0) {printf("PID: %d, PPID: %d\n", getpid(), getppid());return -1;}//父进程循环,便于观察while(1) {sleep(1);}return 0;
}

2. 守护进程

【1】概念:是一种生存期很长的进程。从操作系统启动开始,在操作系统关闭时终止。

  • 所有守护进程都以root(用户ID为0)的优先权运行。
  • 守护进程没有控制终端,一直在后台运行。
  • 守护进程的父进程都是init进程。

【2】创建守护进程的步骤:见守护进程 | 爱编程的大丙 (subingwen.cn)。

3. 孤儿进程

  • 概念:父进程结束了,但是子进程还在运行,那么此时子进程就是孤儿进程。孤儿进程由init进程(1号进程)来回收。
  • 领养机制引入:进程的用户区资源可以自己释放,但是内核区资源需要由父进程释放。而孤儿进程的父进程已经结束。因此,为了释放孤儿进程的内核区资源,让1号进程来领养它,进而释放其内核区的task_struct结构体。

程序示例:通过fork创建子进程,同时让父进程退出,那么子进程就是孤儿进程。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(int argc, char **argv)
{//创建子进程pid_t pid = fork();if (pid < 0) {perror("创建子进程失败");return -1;}//父进程退出if (pid > 0) {printf("PID: %d, PPID: %d\n", getpid(), getppid());return -1;}//子进程成为孤儿进程if (pid == 0) {sleep(2);printf("PID: %d, PPID: %d\n", getpid(), getppid());return -1;}return 0;
}


五、相关函数

1. wait函数

【1】头文件:#include <sys/types.h>、#include <sys/wait.h>

【2】函数原型:pid_t wait(int *wstatus);

【3】参数说明:wstatus是传出的参数,存放子进程退出时的信息。例如:wait(&status);

取出整形变量status中的数据需要使用一些宏函数:

  • WIFEXITED(status)用于判定是否是正常结束,是的话返回真;WEXITSTATUS(status)取出对应的进程退出码。
  • WIFSIGNALED(status)用于判定是否是异常结束,是的话返回真;WTERMSIG(status)取出对应的进程退出码。
  • WIFSTOPPED(status)用于判定是否是暂停子进程的返回,是的话返回真;WSTOPSIG(status)取出对应的进程退出码。

【4】功能:父进程等待子进程退出并回收,避免僵尸进程和孤儿进程产生。

【5】返回值:成功则返回子进程的PID,失败返回-1。

【6】注意:wait函数等待所有的子进程退出。

示例程序:演示子进程异常退出,父进程对退出码进行处理。

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc, char **argv)
{//创建子进程pid_t pid = fork();if (pid < 0) {perror("创建子进程失败");return -1;}//子进程:打印信息,异常退出if (pid == 0) {printf("PID: %d, PPID: %d\n", getpid(), getppid());int i = 3, j = 0, k = i/j;//由于除0异常退出}//父进程:阻塞等待子进程退出,将退出码保存int status;pid_t ret = wait(&status);if (ret < 0) {printf("回收失败\n");return 0;} else {printf("回收成功,子进程PID:%d\n", ret);}//父进程:处理退出码if(WIFEXITED(status)) {printf("正常退出:%d\n", WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf("异常退出:%d\n", WTERMSIG(status));} else if (WIFSTOPPED(status)) {printf("暂停退出:%d\n", WSTOPSIG(status));} else {printf("未知退出\n");}return 0;
}

2. waitpid函数

【1】头文件:#include <sys/types.h>、#include <sys/wait.h>

【2】函数原型:pid_t waitpid(pid_t pid, int *wstatus, int options);

【3】参数说明:

  • pid: 
    • -1:回收所有的子进程资源, 和wait()是一样的。
    • >0:指定回收某一个进程的资源。
    • 0:回收当前进程组的所有子进程。
    • <-1:pid 的绝对值代表进程组ID,表示要回收这个进程组的所有子进程资源。
  • wstatus:与wait一样。
  • options:控制函数是阻塞还是非阻塞。
    • 0:函数的行为是阻塞的。
    • WNOHANG:函数的行为是非阻塞的。
    • WUNTRACED:若某个pid子进程已暂停,并且其状态自从暂停以来没有报告过,就返回真。

【4】返回值:①若函数是非阻塞的,并且子进程还在运行就返回0;②成功返回子进程PID,失败返回-1.

【5】功能:是wait函数的升级版,可以指定为阻塞或非阻塞,可以等待一个进程或多个进程。

阻塞示例:可以达到与wait相同的效果。

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc, char **argv)
{//创建子进程pid_t pid = fork();if (pid < 0) {perror("创建子进程失败");return -1;}//子进程:打印信息,异常退出if (pid == 0) {printf("PID: %d, PPID: %d\n", getpid(), getppid());int i = 3, j = 0, k = i/j;//由于除0异常退出}//父进程:阻塞等待子进程退出,将退出码保存int status;pid_t ret = waitpid(-1, &status ,0);if (ret < 0) {printf("回收失败\n");return 0;} else {printf("回收成功,子进程PID:%d\n", ret);}//父进程:处理退出码if(WIFEXITED(status)) {printf("正常退出:%d\n", WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf("异常退出:%d\n", WTERMSIG(status));} else if (WIFSTOPPED(status)) {printf("暂停退出:%d\n", WSTOPSIG(status));} else {printf("未知退出\n");}return 0;
}

非阻塞示例:创建3个子进程形成进程扇,调用waitpid的非阻塞方式来回收子进程。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>int main(int argc, char **argv)
{//创建3个子进程,形成进程扇pid_t pid = getpid();//默认赋值为当前pidfor (int i = 0; i < 3; ++i) {pid = fork();if (pid == 0) {break;}}//父进程非阻塞释放所有子进程if (pid== 0) {//子进程printf("子进程PID: %d, PPID: %d", getpid(), getppid());} else {//父进程while (1) {int status;pid_t ret = waitpid(-1, &status, WNOHANG);if (ret < 0) {printf("回收失败,或者所有子进程已经被回收\n");break;} else if (ret == 0) {printf("子进程运行中,继续等待\n");} else {printf("回收成功!子进程PID: %d\n", ret);if (WIFEXITED(status)) {printf("子进程正常退出,退出状态码:%d\n", WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf("子进程异常退出,退出状态码:%d\n", WTERMSIG(status));} else if (WIFSTOPPED(status)) {printf("子进程暂停退出,退出状态码:%d\n", WSTOPSIG(status));} else {printf("未知退出\n");}}}}return 0;
}

3. execl函数

【1】背景:当我们想要在子进程中运行系统中其它的可执行程序,那么就可以调用exec族的函数。调用后,当前子进程的用户区数据全部被目标可执行程序所覆盖,只有内核区还残留之前的数据。(子进程算是一个外壳,运行的可执行程序才算是实体)

【2】头文件:#include <unistd.h>

【3】函数原型:int execl(const char *path, const char *arg, ...);

【4】参数说明:

  • path:要启动的可执行程序的路径, 推荐使用绝对路径。
  • arg:ps -aux查看进程时启动的进程的名字,一般和要启动的可执行程序名相同。
  • ...:执行命令行所需要的参数,最后以NULL结尾表示结束。

【5】返回值:成功没有返回值,失败返回-1.

4. execlp函数

【1】功能:该函数常用于执行已经设置了环境变量的可执行程序。即该函数会自动搜索系统的环境变量PATH,因此该函数执行可执行程序不需要指定具体路径,只需指出名字。

【2】函数原型:int execlp(const char *file, const char *arg, ...);

【3】参数说明:file表示可执行程序的名字。其他参数与execl函数相同。

程序示例:创建子进程来执行ps -aux命令。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main(int argc, char **argv)
{//创建一个子进程pid_t pid = fork();if (pid < 0) {perror("创建子进程失败");return -1;}//父进程执行if (pid > 0) {printf("父进程执行中...\n");pid_t ret = wait(NULL);if (ret < 0) {printf("回收子进程失败\n");} else {printf("回收子进程成功,子进程PID: %d\n", ret);}}//子进程执行psif (pid == 0) {execl("/bin/ps", "ps", NULL);printf("若执行该语句,则说明执行ps程序失败\n");}return 0;
}

5. system函数

【1】功能:简化execl函数的调用,不需要手动创建子进程。

【2】原理:system函数内部会构建一个子进程,由子进程调用exec族函数。

【3】头文件:#include <stdlib.h>

【4】函数原型:int system(const char *command);

示例程序:调用system函数执行ps命令。

#include <stdlib.h>int main(int argc, char **argv)
{system("ps -aux");return 0;
}

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

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

相关文章

2024年无线领夹麦克风选购指南,领夹麦克风哪个品牌好

"领夹麦克风"这个名词对于大多数人可能还比较陌生&#xff0c;但在互联网专业人士和短视频制作者的世界里&#xff0c;它却是一个不可或缺的工具。如果你有志于成为短视频领域的创作者&#xff0c;或者想要参与视频拍摄、直播等多媒体内容的制作&#xff0c;那么了解…

计算机工具软件安装攻略:Chrome浏览器下载安装及使用

1 Chrome简介 Chrome是谷歌公司开发的一款免费网页浏览器它快速、稳定、安全拥有简洁流畅的界面和丰富的应用程序内置了强大的谷歌搜索引擎。Chrome使用Blink浏览器引擎和V8 JavaScript引擎支持多种插件和扩展程序让浏览网页更便捷。它可以与Android手机良好同步支持跨设备浏览…

写给弟弟高考报考碎碎念话痨的话

1.学校>专业&#xff0c;无论是学校的资源还是后面的升学与就业&#xff0c;保研升学什么的等等各方面工资水平就业补贴各个方面都是按档次来的&#xff0c;985>211>普本 2.城市略大于学校&#xff0c;优先考虑大城市&#xff0c;机会多的意思是&#xff0c;人才…

经典SM2密文转 ASN1/DER编码格式

最近在国四协议转发国家平台的事宜。新协议要求国四报文要以加密形式转发给国家平台。可以是国密4&#xff0c;国密2.如果使用国密2的时候&#xff0c;注意密文要使用ASN1/DER编码格式。于是我参考了以下几个链接的内容&#xff1a; 基于OpenSSL&#xff0c;实现SM2密文数据的…

Vue Router 导航守卫,多次执行的解决方案

Vue Router 是 Vue.js 官方提供的路由器,它用于处理单页应用(SPA)中的路由导航。在 Vue Router 中,导航守卫是非常重要的功能,它可以在路由跳转之前或之后执行一些特定的操作。但是,如果你不小心,导航守卫可能会多次执行,这可能会导致一些问题。本文将介绍如何避免导航…

cpu scheduling cpu调度

soft real-time Vs hard real-time scheduling Real-Time CPU Scheduling Can present obvious challengesSoft real-time systems – Critical real-time tasks have the highest priority, but no guarantee as to when tasks will be scheduledHard real-time systems – …

“Allegro评论管理:高效处理评价,提升顾客满意度”

波兰Allegro平台以其庞大的用户基础和丰富的商品种类&#xff0c;成为波兰乃至欧洲电商市场中的一颗璀璨明珠。如何高效管理和优化顾客评价&#xff0c;成为每个商家亟待解决的核心问题。正是基于这一背景&#xff0c;“无忧易售”——一款专注于Allegro评价管理的功能上线了&a…

【报错】在终端中输入repo命令后系统未能识别这个命令

1 报错 已经使用curl命令来下载repo工具,但是在终端中输入repo命令后系统未能识别这个命令。 2 分析 通常是因为repo

使用 Mac 数据恢复从 iPhoto 图库中恢复照片

我们每个人都会遇到这种情况&#xff1a;在意识到我们不想丢失照片之前&#xff0c;我们会永久删除 iPhoto 图库中的一些照片。永久删除这些照片后&#xff0c;是否可以从 iPhoto 图库中恢复照片&#xff1f;本文将指导您使用免费的 Mac 数据恢复软件从 iPhoto 中恢复照片。 i…

2024软件设计师笔记之考点版(一考就过):1-10

软件设计师之一考就过:成绩版 考点1:CPU、指令 真题1:CPU 执行算术运算或逻辑运算时,常将源操作数和结果暂存在(累加器(AC))中。 真题2:在程序的执行过程中,Cache与主存的地址映射是由(硬件自动)完成的。 真题3:计算机执行程序时,内存分为静态数据区、代码区、…

SQL Server 数据库分页技术详解:选择最佳方法优化查询性能”。

当今数据驱动的应用程序中&#xff0c;数据库分页技术在优化查询性能和提升用户体验中扮演着重要角色。在 SQL Server 环境下&#xff0c;开发者面对大数据集时&#xff0c;常常需要选择合适的分页方法以平衡功能需求和性能优化。本文将详细介绍 SQL Server 中几种主要的分页技…

【漏洞复现】华测监测预警系统——SQL注入漏洞

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 华测监测预警系统2.2版本存在sql注入&#xff0c;UserEdit接口S…

文华6声音预警公式-macd+kdj共振信号买卖点提示主图指标公式源码

文华6声音预警公式-macdkdj共振信号买卖点提示主图指标公式源码 指标公式逻辑&#xff1a; KDJC和MACDJC同时金叉时在K线的下面标记买字&#xff0c; KDSC和MACDSC同时死叉时候在K线上面标记卖字。 同时添加一下声音 指标公式源码&#xff1a; RSV:(CLOSE-LLV(LOW,9))/(H…

【华为OD机试B卷】解压报文、压缩报文还原(C++/Java/Python)

题目 题目描述 为了提升数据传输的效率,会对传输的报文进行压缩处理。输入一个压缩后的报文,请返回它解压后的原始报文。压缩规则:n[str],表示方括号内部的 str 正好重复 n 次。注意 n 为正整数(0 < n <= 100),str只包含小写英文字母,不考虑异常情况。输入描述 输…

零刻SER8 8845HS设置RAID磁盘阵列教程

SER8内置两个NVme硬盘位&#xff0c;支持硬盘RAID功能&#xff0c;目前支持以下几种RAID模式。 Volume&#xff08;卷&#xff09;&#xff1a;将多块硬盘拼接成一个大硬盘&#xff0c;也称为JBOD&#xff08;Just a Bunch Of Disks&#xff09;。它不要求硬盘容量相同&#xf…

干货收藏之追片神器

&#x1f3ac;追片神器&#x1f525;&#xff1a;cchifilm.com - 你的专属电影世界&#x1f31f; 在这个看脸的时代&#xff0c;我们都需要一款「追剧必备」的神器&#xff0c;今天我要安利给大家的是——cchifilm.com&#xff01;这是一个聚集了全球电影資訊和讨论的神奇网站…

【SQL Server数据库】简单查询

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

使用 ks 安装 mysql

https://www.kubesphere.io/zh/docs/v3.3/application-store/built-in-apps/mysql-app/ 准备工作 您需要启用 OpenPitrix 系统。如何启用&#xff1f; 动手实验 步骤 1&#xff1a;从应用商店部署 MySQL 在 demo-project 的概览页面&#xff0c;点击左上角的应用商店。找到 …

昇思25天学习打卡营第二天|张量 Tensor

背景 华为组织了昇思25天学习学习营&#xff0c;提供免费算力&#xff0c;算力支持是昇腾Ascend 910芯片96G内存&#xff0c;很给力。 第一天的学习内容可以阅读文章&#xff1a; 昇思25天学习打卡营第一天|快速入门 学习内容 今天的学习内容是张量。如果线性代数学的好的同…

求字符串中所有整数的最小和(100%用例) C卷(JavaPythonC++Node.jsC语言)

输入字符串s,输出s中包含所有整数的最小和 说明 1. 字符串s,只包含 a-z A-Z +- ; 2. 合法的整数包括 1) 正整数 一个或者多个0-9组成,如 0 2 3 002 102 2)负整数 负号 - 开头,数字部分由一个或者多个0-9组成,如 -0 -012 -23 -00023 输入描述: 包含数字的字符串 …