【嵌入式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手机良好同步支持跨设备浏览…

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…

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

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

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

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

【漏洞复现】华测监测预警系统——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…

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

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

【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天学习打卡营第一天|快速入门 学习内容 今天的学习内容是张量。如果线性代数学的好的同…

突发!OpenAI停止不支持国家API,7月9日开始执行

6月25日凌晨&#xff0c;有部分开发者收到了OpenAI的信&#xff0c;“根据数据显示&#xff0c;你的组织有来自OpenAl目前不支持的地区的API流量。从7月9日起&#xff0c;将采取额外措施&#xff0c;停止来自不在OpenAI支持的国家、地区名单上的API使用。” 但这位网友表示&am…

MySQL 5.7.42 主从复制环境搭建

MySQL 5.7.42 主从复制环境搭建 下载MySQL二进制包操作系统环境配置安装过程搭建从库 本次安装环境&#xff1a; OS版本&#xff1a;Red Hat Enterprise Linux Server release 6.8 (Santiago) MySQL版本&#xff1a;5.7.42 架构&#xff1a;同一台机器&#xff0c;多实例安装搭…

数字图像分析(第一部分)

文章目录 第2章 图像数字化数字化采样与量化像素的邻域像素的距离图像采集网络**离散直线性**距离变换**第3章 图像变换可分离和正交图像变换2D DFT变换及其本质**哈达玛变换KL变换(PCA)第4章 形态学二值形态学膨胀和腐蚀开启和闭合击中-击不中变换二值形态学实用算法噪声滤除目…

YOLOv10:无需NMS的目标检测新范式(强的离谱)

本本来自公众号“AI大道理”。 YOLO系列一直存在nms&#xff0c;然而nms非常耗时&#xff0c;且总给人一种不简单&#xff0c;不直接的感觉。能不能去掉nms&#xff1f; YOLOv10终于实现了&#xff01; YOLOV10的改进 1、Backbone 2、Neck 3、Head与双标签分配 4、Loss计算…

看看人家的单点登录认证系统,确实清新优雅!

插&#xff1a; AI时代&#xff0c;程序员或多或少要了解些人工智能&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家(前言 – 人工智能教程 ) 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家…

Windows安装dig命令

背景 Windows环境下 cmd 执行 dig 命令提示“dig不是内部或外部命令”&#xff0c;需要在Windows环境下安装dig命令 下载dig软件 可通过网络搜索“Windows平台的Bind_9.16.16”&#xff0c;或者访问https://download.csdn.net/download/m0_46665077/62245100 下载 Windows…

Hive笔记-4

240618-Hive笔记-4 4.2 Insert 4.2.1 将查询结果插入表中 1) 语法 INSERT (INTO | OVERWRITE) TABLE tablename [PARTITION (partcol1val1,partcol2val2 ...)] select_stamement; 关键字说明: (1) INTO: 将结果追加到目标表 (2) OVERWRITE: 用结果覆盖原有数据 2) 案例…

表单prop必填验证根据el-radio-group的值来动态绑定

1、radio的值为5时输入框是必填&#xff0c;其余时候是非必填 2、看图 3、代码 data() {return {optForm:{type:,remark:,},rules:{type:[{ required: true,trigger: change,message:该项为必填项}],remark:[]}};},watch: {"optForm.type"(newVal, oldVal) {this.$…