进程与线程-----C语言经典题目(8)
一.什么是进程
定义:
进程指的是程序在操作系统内的一次执行过程。它不只是程序代码,还涵盖了程序运行时的各类资源与状态信息。包括创建、调度、消亡。
进程的状态(ps -aux):
就绪状态:进程已经准备好运行,正在等待操作系统分配CPU资源。
运行状态:进程正在CPU上执行。
阻塞状态:进程因为等待某个事件(如I/O操作完成)而暂时无法继续执行。
可唤醒等待态S:进程挂起等在某个资源到达后继续向下执行。
不可唤醒等待态D:进程任务挂起直到等到某个信号来了才继续向下执行。
暂停态T:进程任务挂起,直到CPU发送指令才能继续向下执行。
僵尸态Z:代码已经执行完毕,空间仍然存在。
结束态X:代码执行完毕,代码被回收。
用fork()创建一个进程:
// 程序的主函数,程序的执行从这里开始
int main()
{// 定义一个 pid_t 类型的变量 pid,用于存储 fork 函数的返回值pid_t pid;// 调用 fork 函数创建一个新的子进程// fork 函数会返回两次,在父进程中返回子进程的进程 ID,在子进程中返回 0,出错时返回 -1pid = fork();// 检查 fork 函数的返回值是否小于 0,如果小于 0 表示创建子进程时出错if (pid < 0) {// 使用 fprintf 函数向标准错误输出流输出错误信息,提示 fork 操作失败fprintf(stderr, "Fork failed\n");// 返回 1 表示程序异常退出return 1;} // 检查 fork 函数的返回值是否等于 0,如果等于 0 表示当前代码在子进程中执行else if (pid == 0) {// 输出提示信息,表明当前是子进程,并使用 getpid 函数获取当前子进程的进程 ID 并打印printf("This is the child process, pid = %d\n", getpid());} // 如果 fork 函数的返回值大于 0,说明当前代码在父进程中执行,返回值即为子进程的进程 IDelse {// 输出提示信息,表明当前是父进程,并打印子进程的进程 IDprintf("This is the parent process, child pid = %d\n", pid);}// 程序正常结束,返回 0return 0;
}
二.在linux系统中使用什么结构表示一个进程?
用task_struct结构体来表示一个进程。这个结构体在linux内核里定义,包含了进程的所有信息,像进程状态、进程ID、优先级、打开的文件等。
task_struct源于linux内核源码中的include/linux/sched.h文件。
里面的volatile long state ,原来表示进程的当前状态。
pid_t pid :进程的 唯一标识符。
struct task_struct *parent :指向父进程的指针。
struct list_head children :子进程链表。
三.系统通过什么区分两个正在运行的a.out?
C语言系统本身并不会区分a.out这个特定的执行文件,而是去区分运行着的进程。
1.进程ID(PID)
每个进程都有独一无二的进程ID(PID)。当启动一个a.out 程序时,操作系统会给它分配一个PID,PID是一个正整数,在系统里是唯一的,操作系统能够借助PID来区分不同的进程。
可以通过getpid()函数获取当前进程的PID。
2.进程控制块(PCB)
操作系统为每个进程都维护了一个进程控制块(PCB),它是一个数据结构,里面包含了进程的各种信息,像PID、进程状态、程序计数器、内存指针、文件描述符等。操作系统会依据PCB来管理和区分不同的进程。
3.父进程ID(PPID)
每个进程都有一个父进程,父进程ID(PPID)同样能用来区分进程。可以用getppid()函数获取当前进程的父进程ID。
4.命令行参数和环境变量
即使是同一个可执行文件a.out ,要是在启动时使用了不同的命令行参数或者环境变量,操作系统也能把他们区分开来。
四.当一个进程开始运行,系统(32bit)给用户层分配的内存空间是多大,有哪些区域。每个区域存储什么东西?
32bit 的系统中,给用户层分配的内存空间通常为4GB,
代码段:
存储内容:存放程序的可执行指令,也就是编译后的机器码。
特性:只读,为了防止程序在运行过程中意外修改自身的指令。
共享,当多个进程运行同一个程序时,这些进程可以共享这一个代码段。
数据段:
存储内容:存储已初始化的全局变量和静态变量,这些变量的值非0。
例如:int a = 10;
BSS段:
存储内容:未初始化的全局变量和静态变量会被存放在BSS段中,在程序开始执行前,系统会自动把这些变量初始化为0。
例如:int a ;
堆:
存储内容:动态分配的内存就存放在堆中,如使用malloc、calloc、realloc。
特性:堆的内存分配是由低地址向高地址增长的,且使用完后需要通过free()来释放内存,否则会造成内存泄漏。
栈:
存储内容:函数调用的上下文,也就是栈帧,存放在栈中。栈帧里包含局部变量、函数参数以及返回地址等信息。
特性:栈的内存分配是从高地址向低地址增长的,它的空间大小是有限的,一旦超出限制就会导致栈溢出。
命令行参数和环境变量:
存储内容:程序运行时的命令行参数以及环境变量存放在这个区域。
位置:位于用户空间的最高地址处。
高地址┌─────────────────────────────────────┐│ ││ 环境变量和命令行参数 ││ │├─────────────────────────────────────┤│ ││ 栈 ││ (向低地址方向增长) ││ │├─────────────────────────────────────┤│ ││ 堆 ││ (向高地址方向增长) ││ │├─────────────────────────────────────┤│ ││ BSS段 ││ (未初始化的全局变量) ││ │├─────────────────────────────────────┤│ ││ 数据段 ││ (已初始化的全局变量) ││ │├─────────────────────────────────────┤│ ││ 代码段 ││ (程序指令) ││ │└─────────────────────────────────────┘
低地址
五.什么是虚拟地址?
虚拟地址是运行程序时 CPU 所生成的地址。
主要功能:
内存隔离:不同进程的虚拟地址空间相互独立,这样一个进程出现问题,不会对其他进程造成影响。
内存抽象化:程序所使用的内存空间是连续的,然而物理内存可能是分散的。
内存保护:通过设置访问权限,能够防止程序对其他进程的内存进行越界访问。
内存共享:不同进程可以共享同一块物理内存,例如共享库。
相关 c 语言代码:
指针实际上就是虚拟地址:
int a = 10;
int *p = &a; // p存储的是变量a的虚拟地址
六.进程的作用是什么?
1.资源分配的基本单位:
系统会给每个进程分配独立的系统资源,像内存空间、文件描述符、CPU 时间片等。
int main()
{// 每个进程都有自己独立的内存空间int pid = fork(); // 创建子进程if (pid == 0) {// 子进程printf("子进程: PID=%d\n", getpid());} else {// 父进程printf("父进程: PID=%d\n", getpid());}return 0;
}
2.实现多任务处理:
借助进程,系统可以同时运行多个程序,也就是实现并发或并行操作。
int main()
{pid_t pid = fork(); // 创建子进程if (pid < 0) {perror("创建进程失败");exit(EXIT_FAILURE);}if (pid == 0) {// 子进程执行新程序execlp("/bin/ls", "ls", "-l", NULL);} else {// 父进程继续执行其他任务printf("父进程继续运行...\n");wait(NULL); // 等待子进程结束}return 0;
}
3.提供隔离环境:
各个进程之间相互隔离,一个进程出现崩溃或者异常,通常不会对其他进程造成影响。
int main()
{pid_t pid = fork();if (pid == 0) {// 子进程故意出错printf("子进程准备崩溃...\n");*((int*)0) = 10; // 访问无效地址,引发段错误} else {// 父进程不受影响printf("父进程继续正常运行\n");sleep(2);}return 0;
}
4.实现程序的并发执行
在处理 I/O 密集型或者计算密集型任务时,通过创建多个进程,可以显著提高程序的执行效率
#define N 5int main()
{int i = 0;for (i = 0; i < N; i++) {pid_t pid = fork();if (pid == 0) {printf("子进程 %d 执行计算任务\n", i);exit(EXIT_SUCCESS);}}// 父进程等待所有子进程结束for (i = 0; i < N; i++) {wait(NULL);}printf("所有子进程执行完毕\n");return 0;
}
5.实现跨进程通信(IPC)
不同进程之间可以通过管道、消息队列、共享内存等机制进行通信,从而实现更复杂的分布式系统。
int main()
{int pipefd[2]; // 创建管道文件描述符数组:pipefd[0]为读端,pipefd[1]为写端char buffer[100]; // 用于存储从管道读取的数据的缓冲区// 创建匿名管道,失败时返回-1并设置errnoif (pipe(pipefd) == -1) {perror("创建管道失败"); // 输出系统错误信息return 1; // 非零返回值表示程序异常退出}pid_t pid = fork(); // 创建子进程,返回值:子进程返回0,父进程返回子进程PIDif (pid == 0) {// 子进程执行区域close(pipefd[0]); // 关闭不需要的读端,避免资源泄漏const char* message = "Hello from child process!";// 向管道写端写入字符串(包含字符串结束符'\0')write(pipefd[1], message, strlen(message) + 1);close(pipefd[1]); // 写入完成后关闭写端,通知读端数据已写完} else {// 父进程执行区域close(pipefd[1]); // 关闭不需要的写端// 从管道读端读取数据到缓冲区,最多读取sizeof(buffer)-1字节read(pipefd[0], buffer, sizeof(buffer));printf("父进程收到消息: %s\n", buffer); // 输出从子进程接收的消息close(pipefd[0]); // 读取完成后关闭读端}return 0; // 程序正常退出
}
七.进程的状态有哪些?
运行态:
进程正在 CPU 上执行指令。在单 CPU 系统中,同一时刻只有一个进程处于运行态
就绪态:
进程已获得除了 CPU 外的所有必要资源,等待操作系统调度执行,一旦 CPU 空闲,就绪队列中的进程将被选中进入运行态。
阻塞态:
进程因等待某个事件(如 I/O 完成、信号量、锁等)而暂停执行。此时进程不占用 CPU 资源,直到等待的事件发生后,进程才会转为就绪态。
新建态:
进程刚刚被创建,但尚未被操作系统完全初始化。此时进程正在分配资源并进入系统。
终止态:
进程已执行完毕或被强制终止,但尚未完全释放资源。在终止态下,进程仍保留一些信息(如退出状态码)供父进程查询,之后才会被系统彻底销毁。
挂起态:
进程暂时被移除内存,存储到磁盘上。挂起态通常分为 就绪挂起(进程在磁盘上就绪,等待被调回内存)和阻塞挂起(进程在磁盘上等待事件)。这种状态常见于内存紧张的系统中。
查看进程状态:
ps命令:查看进程的当前状态(R 表示运行,S 表示睡眠,D 表示不可中断睡眠,T 表示停止,Z 表示僵尸进程)。
/proc/[pid]/status 文件:包含进程的详细状态信息。
系统调用:如wait()、waitpid() 获取子进程的终止状态。
八.进程相关命令有哪些?分别干什么的?
1.fork()
这个系统调用的作用是创建一个子进程,新创建的子进程几乎是父进程的副本。
子进程会获取父进程的数据空间、堆和栈的拷贝。
返回值:在父进程中返回子进程的 PID(进程ID),在子进程中返回0,如果返回-1,就表明创建进程失败。
int main()
{pid_t pid = fork();if (pid < 0) {perror("fork failed");return 1;}else if (pid == 0) {printf("子进程: PID = %d\n", getpid());} else {printf("父进程: 子进程PID = %d, 父进程PID = %d\n", pid, getpid());}return 0;
}
2.vfork()
vfork()也是创建子进程,但与fork()有区别,vfork()创建的子进程会和父进程共享地址空间,而且在子进程调用exec()或者exit()之前,父进程会被阻塞。
3.exec()系列函数
这一系列函数的作用是用新的程序替换当前进程的映像。即当调用exec()之后,当前进程的代码段、数据段和堆栈都会被新程序替换。
常见的有:execl(),execv(),execle(),
4.wait()和waitpid()
主要用于父进程等待子进程结束,并且可以获取子进程的终止状态。
wait(&status):父进程会阻塞,直到任意一个子进程终止。
waitpid(pid,&status,options):父进程等待特定 PID 的子进程,或者通过选项设置为非阻塞模式。
5.getpid()和getppid()
getpid():返回当前进程的 PID。
getppid():返回当前进程父进程的 PID。
6.exit()和 _exit()
用于终止当前进程。
exit(status):会刷新一下缓冲区,然后终止进程。
_exit(status):直接终止进程。
7.system()
作用是执行一个 shell 命令。它会创建一个子进程来执行指定的命令,父进程会等待子进程结束。
int main()
{system("ls -l"); // 执行ls -l命令return 0;
}
8.kill()
用于向进程发送信号,如终止进程、暂停进程等。
9.signal()和sigaction()
用于处理信号。
10.setsid()
用于创建一个新的会话。
九.通过哪个函数新建进程,函数返回值的含义,父子进程关系?
用fork()函数即可创建新进程。
1.函数原型与头文件
#include <unistd.h>
pid_t fork(void);
2.返回值的含义
负值:表面进程创建失败,可能是系统资源不足,或者进程数量达到了上限。
零:这是子进程的返回结果,子进程可以通过getppid()来获取父进程的 ID。
正整数:这是父进程的返回结果,返回的数值是新创建的子进程的 ID。
3.父子进程之间的关系
相同点:
子进程会复制父进程的代码段、数据段、堆和栈等内存空间。
子进程会继承父进程的文件描述符、信号处理方式以及当前工作目录。
不同点:
进程 ID(PID)不一样,子进程的 PID 是唯一的。
父进程 ID(PPID)不同,子进程的 PPID 是创建它的父进程的 PID。
子进程的计时器会重新开始计时。
4.执行流程
调用fork()之后,父子进程会并发执行,但执行顺序由操作系统调度器决定。
子进程从fork()返回处开始执行。
int main()
{pid_t pid = fork();if (pid < 0) {perror("fork failed");return 1;} else if (pid == 0) {// 子进程执行的代码printf("子进程: PID = %d, PPID = %d\n", getpid(), getppid());} else {// 父进程执行的代码printf("父进程: PID = %d, 子进程PID = %d\n", getpid(), pid());}return 0;
}
10.进程退出后,需要注意什么。如何避免僵尸进程的产生?
主要要避免僵尸进程的出现。
僵尸进程的形成:
当子进程终止时,它的进程描述符不会立刻被释放,而是会保留下来,直至父进程读取到子进程的退出状态信息。要是父进程没有调用wait()或waitpid()来获取子进程的状态,子进程就会变成僵尸进程。
僵尸进程的坏处:
尽管僵尸进程不会占用太多系统资源,但如果这类进程数量过多,就可能导致系统的进程表被占满,使得新进程无法创建。
资源释放状况:
子进程终止后,它所占用的大部分资源,像内存、文件描述符等,都会被系统回收。
但进程描述符依然会保留,直到父进程处理完相关状态。
如何避免:
1.父进程主动等待子进程结束:
父进程可以通过调用wait()或waitpid()来获取子进程的退出状态,从而让子进程的资源得到释放。
int main()
{pid_t pid = fork();if (pid < 0) {perror("Fork failed");return 1;} else if (pid == 0) {// 子进程printf("Child process (PID=%d) exiting...\n", getpid());exit(EXIT_SUCCESS);} else {// 父进程printf("Parent process (PID=%d) waiting...\n", getpid());int status;wait(&status); // 等待子进程结束printf("Child process exited with status %d\n", WEXITSTATUS(status));}return 0;
}
2.父进程忽略子进程的退出信号
父进程可以通过设置 SIGCHLD 信号的处理方式为SIG_IGN,让内核自动清理子进程。这样就无需父进程调用wait()了。
int main()
{// 设置忽略 SIGCHLD 信号,让内核自动清理子进程signal(SIGCHLD, SIG_IGN);pid_t pid = fork();if (pid < 0) {perror("Fork failed");return 1;} else if (pid == 0) {// 子进程printf("Child process (PID=%d) exiting...\n", getpid());exit(EXIT_SUCCESS);} else {// 父进程可以继续执行其他任务,无需等待子进程printf("Parent process (PID=%d) continuing...\n", getpid());sleep(2);}return 0;
}
3.采用非阻塞方式检查子进程状态
父进程可以使用waitpid()并传入 WNOHANG 参数,以非阻塞的方式查询子进程是否已经终止。
int main()
{pid_t pid = fork();if (pid < 0) {perror("Fork failed");return 1;} else if (pid == 0) {// 子进程printf("Child process (PID=%d) sleeping...\n", getpid());sleep(2);printf("Child process exiting...\n", getpid());exit(EXIT_SUCCESS);} else {// 父进程printf("Parent process (PID=%d) working...\n", getpid());int status;pid_t result;// 循环检查子进程状态,不阻塞父进程while ((result = waitpid(pid, &status, WNOHANG)) == 0) {printf("Parent: Child is still running...\n");sleep(1);}if (result == pid) {printf("Parent: Child exited with status %d\n", WEXITSTATUS(status));}}return 0;
}
十一.在子进程中需要执行一个外部可执行程序需要怎么做。与原来子进程相比发生什么变化?
需要用到exec系列函数。
执行外部程序方法
1.运用fork()函数创建出子进程。
2.在子进程中调用exec系列函数,像execl 、execv、execle、execve、execlp、execvp
int main()
{pid_t pid = fork(); if (pid < 0) {perror("fork失败"); // 输出错误信息exit(EXIT_FAILURE); // 终止程序} else if (pid == 0) {// 子进程执行区域printf("子进程开始执行外部程序...\n");// 调用execl执行/bin/ls命令// 参数1:可执行文件路径// 参数2:命令名(argv[0])// 参数3及后续:命令行参数(以NULL结尾)execl("/bin/ls", "ls", "-l", NULL);// 若execl返回,说明调用失败perror("execl失败"); // 输出错误原因exit(EXIT_FAILURE); // 子进程异常退出} else {// 父进程执行区域printf("父进程等待子进程结束...\n");// 等待子进程终止// wait(NULL)会阻塞父进程直到任意子进程结束wait(NULL); printf("子进程已结束\n");}return 0;
}
子进程发生的变化
1.全新的程序映像
子进程原本的程序代码会被外部程序的代码所取代,而且程序的全局变量也会被重置。
2.新的进程上下文
子进程会拥有新的程序计数器、堆栈指针以及寄存器值。
3.文件描述符保留
子进程在调用exec之前打开的文件描述符,在exec调用之后依然会保持打开状态,除非这些文件描述符设置了 FD_CLOEXEC 标志
4.进程 ID 保持不变
子进程的 PID 不会改变,只是运行的程序发生了变化
5.内存空间重置
子进程原来的内存内容会被丢弃,转而加载新程序的内存映像。
十二.什么是线程?
线程属于程序能够独立运行的最小执行单元。存在于进程内部,和同一进程的其他线程共享全局变量、文件描述符等资源,不过各自拥有独立的栈空间与程序计数器。
线程的特点
轻量级:线程的创建和切换开销比进程小,因为他们共享进程的资源。
资源共享:同一进程内的线程共享内存空间、文件句柄等资源,便于数据交换和通信。
并发执行:多个线程可以并发执行,提高程序和执行效率。
独立执行流程:每个线程有自己的执行路径和状态。
线程基本操作:
通常通过 POSIX 线程库来实现多线程。
// 线程函数,线程启动后会执行这个函数
void* thread_function(void* arg)
{int thread_id = *(int*)arg;printf("线程 %d 正在运行\n", thread_id);// 线程执行一些工作...pthread_exit(NULL); // 线程退出
}int main()
{pthread_t thread1, thread2;int id1 = 1, id2 = 2;// 创建两个线程if (pthread_create(&thread1, NULL, thread_function, &id1) != 0) {perror("线程创建失败");return 1;}if (pthread_create(&thread2, NULL, thread_function, &id2) != 0) {perror("线程创建失败");return 1;}// 等待线程结束if (pthread_join(thread1, NULL) != 0) {perror("等待线程失败");return 1;}if (pthread_join(thread2, NULL) != 0) {perror("等待线程失败");return 1;}printf("所有线程已完成\n");return 0;
}
编译时需要链接 pthread 库 :-lpthread
线程同步:
由于多线程共享资源,可能会引发竟态条件。需要使用同步机制,如互斥锁、信号量等。
使用互斥锁:
int shared_counter = 0;
pthread_mutex_t mutex;void* increment(void* arg)
{int i = 0;for (i = 0; i < 100000; i++) {pthread_mutex_lock(&mutex); // 加锁shared_counter++;pthread_mutex_unlock(&mutex); // 解锁}pthread_exit(NULL);
}int main()
{pthread_t t1, t2;pthread_mutex_init(&mutex, NULL); // 初始化互斥锁pthread_create(&t1, NULL, increment, NULL);pthread_create(&t2, NULL, increment, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_mutex_destroy(&mutex); // 销毁互斥锁printf("共享计数器的值: %d\n", shared_counter);return 0;
}
十三.进程和线程的区别?
本质差异:
进程:是程序在操作系统中的一次执行实例,是系统进行资源分配和调度的基本单位。
线程:是进程中的一个执行单元,是 CPU 调度和分派的基本单位。
内存空间:
进程:不同进程之间的内存空间是相互独立的,一个进程不能直接访问另一个进程的内存。
线程:同一进程内的线程共享进程的内存空间,他们可以直接访问进程中的全局变量和堆内存。
创建开销:
进程:创建进程时,操作系统需要为其分配独立的内存空间和系统资源,开销比较大。
线程:创建线程时,由于共享进程的资源,只需要为线程分配栈空间和程序计数器等少量资源,开销比较小。
通信方式:
进程:进程间通信(IPC)需要使用特定的机制,如管道、消息队列、共享内存、套接字等。
线程:线程间通信可以直接通过共享全局变量来实现。这种方式简单高效。但要注意线程同步的问题,避免竟态条件。
调度和切换:
进程:进程的调度和切换需要保存和恢复进程的上下文,开销比较大。
线程:线程的调度和切换只需要保存和恢复线程的上下文,开销比较小。
健壮性:
进程:一个进程崩溃不会影响其他进程,因为他们的内存空间是独立的。
线程:一个线程崩溃可能会导致整个进程崩溃,因为他们是共享同一内存空间。
// 线程函数
void* thread_function(void* arg)
{printf("这是一个线程,线程ID: %lu\n", pthread_self());return NULL;
}int main()
{// 创建进程pid_t pid = fork();if (pid < 0) {// 出错处理perror("fork失败");exit(EXIT_FAILURE);} else if (pid == 0) {// 子进程printf("这是子进程,进程ID: %d\n", getpid());} else {// 父进程printf("这是父进程,进程ID: %d,子进程ID: %d\n", getpid(), pid);// 创建线程pthread_t thread_id;int result = pthread_create(&thread_id, NULL, thread_function, NULL);if (result != 0) {// 出错处理perror("线程创建失败");exit(EXIT_FAILURE);}// 等待线程结束pthread_join(thread_id, NULL);printf("线程已结束\n");}return 0;
}
相关文章:
进程与线程-----C语言经典题目(8)
一.什么是进程 定义: 进程指的是程序在操作系统内的一次执行过程。它不只是程序代码,还涵盖了程序运行时的各类资源与状态信息。包括创建、调度、消亡。 进程的状态(ps -aux): 就绪状态:进程已经…...
lstm用电量预测+网页可视化大屏
视频教学: 训练结果: 详细代码: import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler from sklearn.model_selection import train_test_split from tensorflow.keras.models import Sequential from tensorflow.keras.layers impo…...
linux blueZ 第六篇:嵌入式与工业级应用案例——在 Raspberry Pi、Yocto 与 Buildroot 上裁剪 BlueZ 并落地实战
本篇面向嵌入式与工业级应用场景,深入讲解如何在各类 Linux 构建系统(Raspberry Pi OS、Yocto、Buildroot)中裁剪、交叉编译与集成 BlueZ,以及在工业网关、资产追踪与蓝牙 Mesh 等典型方案中的落地实例与注意要点,帮助你打造稳定、可维护、低功耗的嵌入式蓝牙产品。 目录 …...
Dev控件RadioGroup 如何设置一排有N个显示或分为几行
1.5个选项 全部横排显示,则Columns 5 2.5个选项 每行分两个,则有三行,则Columns 2...
AOSP Android14 Launcher3——Launcher的状态介绍LauncherState类
Launcher3中有一个跟Launcher状态相关的类,叫LauncherState LauncherState 是 Launcher3 中定义各种用户界面状态的抽象基类。你可以把它想象成一个状态机,定义了 Launcher 可能处于的不同视觉和交互模式,例如主屏幕、所有应用列表、最近任务…...
Redis 笔记(三)-Redis 基本知识及五大数据类型
一、redis 基本知识 redis 默认有 16个 数据库,config get databases 查看数据库数量 127.0.0.1:6379> config get databases # 查看数据库数量 1) "databases" 2) "16"默认使用的是第 0个 16 个数据库为:DB 0 ~ DB 15&am…...
Linux——线程(2)线程互斥(锁)
知识回顾 在学习本篇内容前,我们需要先回顾一下几个概念。 临界资源:多线程执行流共享的资源就叫做临界资源 临界区:每个线程内部,访问临界资源的代码,就叫做临界区 互斥:任何时刻,互斥保证有…...
深度解析:具身AI机器人领域最全资源指南(含人形机器人,多足机器人,灵巧手等精选资源)
💡 你是否在寻找具身人工智能(Embodied AI)领域的研究资源?是否希望有一个系统性的资源集合来加速你的研究?今天给大家推荐一个重磅项目! 🌟 为什么需要这个项目? 具身人工智能是一…...
组件之间的信息传递的四种方法!!【vue3 前端】
迎万难 赢万难! 目录 1. 使用 defineProps 传递数据:2. 使用。defineEmits 发送事件:3. 使用 Provide / Inject:4. 使用状态管理(如 Pinia): 1. 使用 defineProps 传递数据: 父组件…...
单片机学习笔记9.数码管
0到99计数 ,段选共阴极 ;0到99计数 ORG 0000H LJMP MAIN ORG 000BH LJMP TIMER0_ISR ORG 0100H; 定义位选控制位 DISPLAY_SELECT BIT 20H.0MAIN:; 定时器 0 初始化MOV TMOD, #01H ; 设置定时器 0 为模式 1MOV TH0, #3CH ; 定时器 0 高 8 位初值,定时 …...
Go 语言 核心知识点
Go 语言(Golang)是由 Google 开发的一种静态类型、编译型语言,设计目标是高效、简洁、并发友好。它借鉴了 C 语言的性能优势,同时引入了现代语言的特性(如垃圾回收、并发原语),并摒弃了传统面向…...
【C++ 类和数据抽象】消息处理示例(2)
目录 一、消息处理系统的核心价值 1.1 现代软件架构中的消息驱动 1.2 消息处理系统的关键组件 二、消息处理系统概述 三、Message类设计 3.1 成员变量 3.2. 成员函数 3.3. 私有辅助函数 四、Folder类设计 五、代码实现 六、数据抽象在消息处理系统中的应用 七、总结…...
kafka 中消费者 groupId 是什么
📚 什么是 groupId? groupId 是 Kafka 里消费者组(Consumer Group)的唯一标识。 同一个 groupId 的消费者,一起共享消费,一条消息只给组内一个消费者处理。不同 groupId 的消费者组,各自独立消…...
单相交直交变频电路设计——matlab仿真+4500字word报告
微♥“电击小子程高兴的MATLAB小屋”获取巨额优惠 1.模型简介 硬件电路采用Altium designer设计,仿真采用Matlab软件 本仿真模型基于MATLAB/Simulink(版本MATLAB 2018Rb)软件。建议采用matlab2018Rb及以上版本打开。(若需要其他…...
Python中的协程(Coroutine)
Python中的协程(Coroutine) 是一种轻量级的异步执行单元,主要用于解决IO密集型任务的性能问题。Python 3.5引入了 async/await 语法,使得协程变得简洁且易于使用。协程的核心是通过事件循环(Event Loop) 来…...
【QT】QT多线程
QT多线程 1.涉及到类和方法示例代码:未重写run函数 2.使用思路3.常用方法4.示例代码1:重写线程run函数现象: 5.示例代码2:多线程显示切换图片,使用公有方法现象: 1.涉及到类和方法 类:QThread 示…...
基于深度学习的医疗诊断辅助系统设计
标题:基于深度学习的医疗诊断辅助系统设计 内容:1.摘要 随着医疗数据的爆炸式增长和深度学习技术的飞速发展,开发基于深度学习的医疗诊断辅助系统具有重要的现实意义。本研究的目的在于设计一个高效、准确的医疗诊断辅助系统,以辅助医生进行更精准的诊断…...
C++ RAII
RAII(Resource Acquisition Is Initialization,资源获取即初始化)是 C 编程中的核心设计理念,用于管理资源的分配和释放。它通过将资源的生命周期绑定到对象的生命周期,利用 C 的自动对象管理机制(主要是栈…...
Linux进程学习【环境变量】进程优先级
进程优先级的基本概念 在 Linux 中,每个进程都有一个优先级,操作系统根据这个优先级来决定进程的执行顺序。优先级越高,进程的执行就越频繁。通常,进程优先级是由以下两个部分构成: 静态优先级(PRI&#x…...
Leetcode:283. 移动零
题目 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0]…...
BIOES 标签的含义
BIOES 标签的含义 B (Begin) 表示一个实体的开始。例如,在句子 “北京是中国的首都” 中,“北京” 作为地点实体的开头,首字会被标注为 B-LOC,后续字可能标注为 I-LOC。 I (Inside) 表示一个实体的中间或内部部分。例如&a…...
mAh 与 Wh:电量单位的深度解析
1. 基础定义与物理意义 1.1 mAh(毫安时) 定义:表示电池以毫安(mA)为单位的电流持续放电 1 小时的电荷量。1 mAh1 mA1 h3.6 C(库仑,电荷单位)局限性:仅反映电池存储的电荷量,未考虑电…...
安卓屏播放语音失败,报错TextToSpeech: speak failed: not bound to TTS engine
最近碰到一个很棘手的问题,无缘无故,之前在Android9.0跑得好好的程序,升级安装系统到Android13后,就发现之前能放的语音,现在放不了了,真是头大,所以我摸索着尝试解决,且看我的解决过…...
C语言学习之结构体
在C语言中,我们已经学了好几种类型的数据。比如整型int、char、short等,浮点型double、float等。但是这些都是基本数据类型,而这些数据类型应用在实际编程里显然是不够用的。比如我们没有办法用一旦数据类型来定义一个”人“的属性。因此这里…...
layui获取无法获取表单数据,data.field一直为空
form.on(submit(*), function(data){console.log(data.field) //当前容器的全部表单字段,名值对形式:{name: value}return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。}); console.log(data.field)一直显示为空࿰…...
「Mac畅玩AIGC与多模态02」部署篇01 - 在 Mac 上部署 Ollama + Open WebUI
一、概述 本篇介绍如何在 macOS 环境下本地部署 Ollama 推理服务,并通过 Open WebUI 实现可视化交互界面。该流程无需 CUDA 或专用驱动,适用于 M 系列或 Intel 芯片的 Mac,便于快速测试本地大语言模型能力。 二、部署流程 1. 环境准备 安装 Homebrew(如尚未安装):/bin…...
量子力学:量子通信
量子通信是利用量子力学原理对信息进行编码、传输和处理的新型通信方式,以下是其详细介绍及业界发展现状: 基本原理 量子叠加态 :量子系统可以处于多个状态的叠加,如光子的偏振方向可以同时处于水平和垂直方向的叠加态ÿ…...
《大型网站技术架构-核心原理与案例分析》笔记
:::info 💡 根据 遗忘曲线:如果没有记录和回顾,6天后便会忘记75%的内容 读书笔记正是帮助你记录和回顾的工具,不必拘泥于形式,其核心是:记录、翻看、思考::: 书名大型网站技术架构-核心原理与案例分析作者…...
log4cpp进阶指南
📝 log4cpp进阶指南 1. 按天切割日志 log4cpp 默认是按文件大小来切割日志的。为了按天切割日志,通常需要自己进行时间判断并手动处理日志文件的切割。 1.1 解决方案 虽然 RollingFileAppender 只支持按大小切割,但你可以使用以下策略&…...
树莓派超全系列教程文档--(43)树莓派内核简介及更新
树莓派内核简介及更新 简介更新 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 简介 Raspberry Pi 内核是 托管在 GitHub 上;更新滞后于上游 Linux内核。上游内核持续更新,而 Raspberry Pi 则将 Linux 内核的长期版本整合…...
第二章、在Windows上部署Dify:从修仙小说到赛博飞升的硬核指南
第1章:安装 wsl (Windows Subsystem for Linux) 上一章我们聊了什么是Dify,这一章我们讲一下怎么才能用Dify。 使用Dify就需要我们在本地部署Dify; 部署Dify就需要用到”Docker“; 要想使用“Docter”就需要用到wsl。 那什么是wsl呢?简单来说就是让你的电脑拥有另一个叫…...
淘宝商品主图标题api接口
1、输入淘宝商品id或者链接,点查询 2、查询淘宝商品主图,商品标题,商品价格,卖家旺旺 3、支持api接口...
小结:BFD
*BFD(双向转发检测,Bidirectional Forwarding Detection)是一种快速、轻量级的故障检测机制,用于检测网络中两点之间的连通性。它广泛应用于各种场景 1. 检测 IP 链路 应用场景: BFD 用于检测两台设备之间的 IP 层连…...
收藏按钮变色问题
1.问题描述 无论是否收藏,收藏按钮都显示黄色,但点击收藏按钮后却能发生颜色变化 2.解决思路 经过调试发现isCollected返回的是整个对象,因此在store的方法里面找到了相应的函数进行修改使得isCollected返回相应的值 修改前: 修…...
小程序发布后,不能强更的情况下,怎么通知到用户需要去更新?
哈喽,我想和大家分享一下我在开发记账小程序时遇到的一个问题,以及我找到的解决办法。 这个记账小程序从一开始,我就特别在意用户的隐私,所以把记账数据都存到了本地缓存里,还做了个手动备份的功能。但系统嘛…...
4.2.2 MySQL索引原理以及SQL优化
文章目录 4.2.2 MySQL索引原理以及SQL优化1. 索引与约束1. 索引是什么2. 索引的目的3. 几种索引4. 约束1.外键2. 约束 vs 索引的区别 5. 索引实现1. 索引存储2. 页3. B树4. B树层高问题5. 自增id6. 聚集索引7. 辅助索引 8. innnodb体系结构1. buffer pool2. change buffer 9. 最…...
02_值相同、类型不同,用 equals() 比较为什么是 false?
02_值相同、类型不同,用 equals() 比较为什么是 false? 场景示例 Map<Long, String> map; Integer keyWord 4; if (map.containsKey(keyWord)) {// ... }结果: → 编译通过,但 containsKey 返回 false,逻辑错…...
leetcode--盛最多水的容器,接雨水
11.盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明:你不…...
AlexNet网络搭建
AlexNet网络模型搭建 环境准备 首先在某个盘符下创建一个文件夹,就叫AlexNet吧,用来存放源代码。 然后新建一个python文件,就叫plot.py吧,往里面写入以下代码,用于下载数据集: # FashionMNIST里面包含了…...
常用第三方库:sqflite数据库应用
常用第三方库:sqflite数据库应用 一、基础概念 1.1 什么是sqflite? sqflite是Flutter官方推荐的SQLite数据库插件,它提供了在Flutter应用中使用SQLite数据库的能力。SQLite是一个轻量级的、嵌入式的关系型数据库,特别适合移动应…...
【论文阅读】-周总结-第5周
1. 【论文阅读24】并行 TCN-LSTM 风电预测模型(2024-02) 链接 论文信息: Liu S, Xu T, Du X, et al. A hybrid deep learning model based on parallel architecture TCN-LSTM with Savitzky-Golay filter for wind power prediction. Ener…...
深入理解 JavaScript 的 typeof 运算符:返回的数据类型
JavaScript 的 typeof 运算符是开发中用于检测值类型的基础工具。虽然看似简单,但其行为存在需要开发者理解的微妙细节。本文将解析 typeof 返回的数据类型,探讨边界案例,并分享类型检查的最佳实践。 typeof 会返回哪些类型? typ…...
前端零基础入门到上班:【Day8】JavaScript 基础语法入门
前端零基础入门到上班:【Day8】JavaScript 基础语法入门(超全!!!) 一、JavaScript 简介二、引入 JavaScript 的三种方式三、变量与常量(var、let、const)3.1 var (传统方式ÿ…...
ppt流程图怎么?ppt流程图模板大全
ppt流程图怎么?ppt流程图剪头模板,ppt流程图模板大全: ppt流程图_模板素材_PPT模板_ppt素材_免抠图片_AiPPTer...
makefile总结
Makefile 学习视频:1、野火的基础入门篇-第32讲 Makefile三要素_哔哩哔哩_bilibili 2、b站视频04 一个稍复杂的Makefile_哔哩哔哩_bilibili 学习资料:第2个视频对应的Make/make.md 无限十三年/CPP - 码云 - 开源中国 ch0_Makefile简介 Makefile是什…...
MIME 类型是个什么东西?
MIME 类型(Multipurpose Internet Mail Extensions)即多用途互联网邮件扩展类型,它是一种标准,用于表示文档、文件或字节流的性质和格式。 最初设计用于电子邮件系统,后来被广泛应用于网页、HTTP 协议等领域࿰…...
javaWeb开发---前后端开发全景图解(基础梳理 + 技术体系)
在现代互联网开发中,前端与后端的分工协作非常重要。本文结合实际架构图,全面梳理前端技术栈、后端技术栈以及服务器端整体流程,帮助初学者建立清晰的整体认知。 一、整体架构概览 系统整体划分为三个主要部分: B端(…...
spring-rabbit的CachingConnectionFactory默认参数导致消费者Channel数量暴增问题解决
文章目录 1.前言2.解决2.1消费监听方法中关闭channel2.2 配置设置两个参数 3.总结 1.前言 由于之前写了一个好用的rabbitmq-spring-boot-start启动器,后面在生产实践之后反馈消费者连接的Channel数量过多,一个消费者的Channel数量可以达到好几百…...
线上JVM调优与全栈性能优化 - Java架构师面试实战
线上JVM调优与全栈性能优化 - Java架构师面试实战 本文通过一场互联网大厂的Java架构师面试,深入探讨了线上JVM调优、OOM定位、死锁定位、内存和CPU调优、线程池调优、数据库调优、缓存调优、网络调优、微服务调优及分布式调优等关键领域。 第一轮提问 面试官&am…...
【KWDB创作者计划】_企业级多模数据库实战:用KWDB实现时序+关系数据毫秒级融合(附代码、性能优化与架构图)
一、技术背景与行业痛点 1.1 多模数据融合挑战 场景痛点: 工业物联网设备每秒产生百万级传感器数据(时序数据)。需关联设备档案(关系数据)生成设备健康报告,传统方案需多数据库跳转,延迟>5…...