进程间通信的七种方法实战演示!值得收藏!

文章目录

  • 前言
  • 一、管道(Pipes)
    • 管道示例代码:
    • 管道示例流程解读:
    • 管道示例运行效果:
  • 二、消息队列(Message Queues)
    • 消息队列示例代码
    • 消息队列示例流程解读:
    • 消息队列示例执行效果
  • 三、共享内存(Shared Memory)
    • 共享内存示例代码
    • 共享内存示例流程解读:
    • 共享内存示例执行效果
  • 四、 信号(Signals)
    • 信号示例代码:
    • 信号示例流程解读:
    • 信号示例执行效果
  • 五、套接字(Sockets)
    • 套接字示例代码:
    • 套接字示例流程解读:
    • 套接字示例执行结果
  • 六、信号量(Semaphores)
    • 信号量示例代码:
    • 信号量示例流程解读:
    • 信号量示例执行结果
  • 七、文件映射(Memory-Mapped Files)
    • 文件映射示例代码:
    • 文件映射示例流程解读:
    • 文件映射示例执行结果
  • 总结


前言

线程和进程间的通讯(Inter-Process Communication, IPC)是操作系统中的一个重要概念,用于实现不同进程或同一进程中的不同线程之间的数据交换和协调。
但是这些概念太多了,容易搞混了,所有特地写了这篇博客来记录这些方式的使用实例,建立大家收藏起来,将来需要复习的时候,再来看一看,能够快速的带你复习一遍!

以下是几个常见的进程间通信的方式:管道、消息队列、共享内存、信号、套接字、信号量、文件映射


提示:以下是本篇文章正文内容,下面案例可供参考

一、管道(Pipes)

管道是一种半双工的通信方式,数据只能单向流动。管道分为两种类型:

匿名管道:仅限于具有亲缘关系的进程之间使用,通常用于父子进程之间的通信。
命名管道(FIFO):可以在任意两个进程之间使用,通过文件系统中的一个特殊文件来标识。

管道示例代码:

以下是一个简单的 C 语言示例,演示如何使用管道实现父子进程间的通信。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h> // 用于 memsetint main() {int pipefd[2];pid_t pid;char buf[100];if (pipe(pipefd) == -1) {perror("pipe");return 1;}pid = fork();if (pid == -1) {perror("fork");return 1;}if (pid == 0) { // 子进程close(pipefd[0]); // 关闭读端write(pipefd[1], "Hello from child", 18);close(pipefd[1]);} else { // 父进程close(pipefd[1]); // 关闭写端memset(buf, 0, sizeof(buf)); // 清空缓冲区ssize_t bytes_read = read(pipefd[0], buf, sizeof(buf) - 1); // 读取数据,留一个字节给终止符if (bytes_read > 0) {printf("Received: %s\n", buf);} else {perror("read");}close(pipefd[0]);wait(NULL);}return 0;
}

管道示例流程解读:

1、创建管道:使用 pipe 函数创建一个管道,该函数返回两个文件描述符,分别用于读取和写入。

2、创建子进程:使用 fork 函数创建一个子进程。fork 返回子进程的 PID,如果返回值为 -1 表示出错,0 表示当前是子进程,其他值表示当前是父进程。

3、关闭不必要的管道端:
在父进程中,关闭管道的端(pipefd[1]),因为子进程只读取数据。
在子进程中,关闭管道的读端(pipefd[0]),因为父进程只写入数据。

4、数据传输:
子进程使用 write 函数向管道中写入数据。
父进程使用 read 函数从管道中读取数据。

5、关闭管道:在完成数据传输后,关闭管道的相应端。

6、等待子进程结束:父进程使用 wait 函数等待子进程结束。

管道示例运行效果:

在这里插入图片描述

二、消息队列(Message Queues)

消息队列是一种更高级的通信方式,允许进程发送和接收消息。消息队列可以存储多个消息,并且可以设置消息的优先级。

消息队列示例代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>#define MAX_MSG_SIZE 256// 定义消息结构体
struct msg_buffer {long msg_type;char msg_text[MAX_MSG_SIZE];
};int main() {key_t key;int msgid;struct msg_buffer message;pid_t cpid;// 生成一个唯一的键值key = ftok("/etc/passwd", 65); // 使用现有的文件 /etc/passwdif (key == -1) {perror("ftok");exit(EXIT_FAILURE);}// 创建消息队列msgid = msgget(key, 0666 | IPC_CREAT);if (msgid == -1) {perror("msgget");exit(EXIT_FAILURE);}// 创建子进程cpid = fork();if (cpid == -1) { // fork 失败perror("fork");exit(EXIT_FAILURE);} else if (cpid == 0) { // 子进程// 子进程接收消息if (msgrcv(msgid, &message, sizeof(message.msg_text), 1, 0) == -1) {perror("msgrcv");exit(EXIT_FAILURE);}printf("Child process received: %s\n", message.msg_text);// 子进程发送消息message.msg_type = 2;strcpy(message.msg_text, "Hello from child");if (msgsnd(msgid, &message, sizeof(message.msg_text), 0) == -1) {perror("msgsnd");exit(EXIT_FAILURE);}exit(EXIT_SUCCESS);} else { // 父进程// 父进程发送消息message.msg_type = 1;strcpy(message.msg_text, "Hello from parent");if (msgsnd(msgid, &message, sizeof(message.msg_text), 0) == -1) {perror("msgsnd");exit(EXIT_FAILURE);}// 父进程接收消息if (msgrcv(msgid, &message, sizeof(message.msg_text), 2, 0) == -1) {perror("msgrcv");exit(EXIT_FAILURE);}printf("Parent process received: %s\n", message.msg_text);// 等待子进程结束wait(NULL);// 删除消息队列if (msgctl(msgid, IPC_RMID, NULL) == -1) {perror("msgctl");exit(EXIT_FAILURE);}}return 0;
}

消息队列示例流程解读:

1、生成唯一键值:使用 ftok 函数生成一个唯一的键值,这个键值用于创建消息队列。这里需要指定一个文件

2、创建消息队列:使用 msgget 函数创建一个消息队列。0666 | IPC_CREAT 表示创建一个新的消息队列,并设置权限。

3、创建子进程:使用 fork 函数创建一个子进程。

4、父进程发送消息:
设置消息类型为 1。
使用 msgsnd 函数将消息发送到消息队列。

5、子进程接收消息:
使用 msgrcv 函数从消息队列中接收类型为 1 的消息。
打印接收到的消息。
设置消息类型为 2。
使用 msgsnd 函数将消息发送回父进程。

6、父进程接收子进程的消息:
使用 msgrcv 函数从消息队列中接收类型为 2 的消息。
打印接收到的消息。

7、删除消息队列:使用 msgctl 函数删除消息队列。

消息队列示例执行效果

在这里插入图片描述

三、共享内存(Shared Memory)

共享内存允许多个进程共享同一块内存区域,是最快速的进程间通信方式。但是需要同步机制(如信号量)来防止竞态条件。

共享内存示例代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/wait.h>#define SHM_SIZE 1024  // 共享内存大小int main() {key_t key;int shmid;char *shm;pid_t cpid;// 生成一个唯一的键值key = ftok("progfile", 65);if (key == -1) {perror("ftok");exit(EXIT_FAILURE);}// 创建共享内存段shmid = shmget(key, SHM_SIZE, 0666 | IPC_CREAT);if (shmid == -1) {perror("shmget");exit(EXIT_FAILURE);}// 将共享内存段连接到进程地址空间shm = shmat(shmid, NULL, 0);if (shm == (char *) -1) {perror("shmat");exit(EXIT_FAILURE);}// 创建子进程cpid = fork();if (cpid == -1) { // fork 失败perror("fork");exit(EXIT_FAILURE);} else if (cpid == 0) { // 子进程// 子进程读取共享内存中的数据printf("Child process reads: %s\n", shm);// 子进程写入共享内存strcpy(shm, "Hello from child");// 子进程断开共享内存if (shmdt(shm) == -1) {perror("shmdt");exit(EXIT_FAILURE);}exit(EXIT_SUCCESS);} else { // 父进程// 父进程写入共享内存strcpy(shm, "Hello from parent");// 父进程等待子进程结束wait(NULL);// 父进程读取共享内存中的数据printf("Parent process reads: %s\n", shm);// 父进程断开共享内存if (shmdt(shm) == -1) {perror("shmdt");exit(EXIT_FAILURE);}// 删除共享内存段if (shmctl(shmid, IPC_RMID, NULL) == -1) {perror("shmctl");exit(EXIT_FAILURE);}}return 0;
}

共享内存示例流程解读:

1、生成唯一键值:使用 ftok 函数生成一个唯一的键值,这个键值用于创建共享内存段。

2、创建共享内存段:使用 shmget 函数创建一个共享内存段。0666 | IPC_CREAT 表示创建一个新的共享内存段,并设置权限。

3、将共享内存段连接到进程地址空间:使用 shmat 函数将共享内存段连接到进程的地址空间。

4、创建子进程:使用 fork 函数创建一个子进程。

5、父进程写入共享内存:
父进程将消息 “Hello from parent” 写入共享内存。

6、子进程读取和写入共享内存:
子进程读取共享内存中的消息并打印。
子进程将消息 “Hello from child” 写入共享内存。

7、父进程读取子进程写入的消息:
父进程等待子进程结束。
父进程读取共享内存中的消息并打印。

8、断开共享内存:使用 shmdt 函数断开共享内存段。

9、删除共享内存段:使用 shmctl 函数删除共享内存段。

共享内存示例执行效果

在这里插入图片描述

四、 信号(Signals)

信号是一种异步通信方式,用于通知进程发生了某些事件。信号可以由操作系统或进程自身发送。

信号示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>// 信号处理函数
void signal_handler(int signum) {if (signum == SIGUSR1) {printf("Received SIGUSR1 signal\n");} else if (signum == SIGUSR2) {printf("Received SIGUSR2 signal\n");}
}int main() {pid_t cpid;struct sigaction sa;// 设置信号处理函数sa.sa_handler = signal_handler;sa.sa_flags = 0;sigemptyset(&sa.sa_mask);if (sigaction(SIGUSR1, &sa, NULL) == -1) {perror("sigaction SIGUSR1");exit(EXIT_FAILURE);}if (sigaction(SIGUSR2, &sa, NULL) == -1) {perror("sigaction SIGUSR2");exit(EXIT_FAILURE);}// 创建子进程cpid = fork();if (cpid == -1) { // fork 失败perror("fork");exit(EXIT_FAILURE);} else if (cpid == 0) { // 子进程// 子进程等待一段时间,让父进程先发送信号sleep(1);// 子进程发送 SIGUSR1 信号给父进程kill(getppid(), SIGUSR1);// 子进程等待一段时间,让父进程处理信号sleep(1);// 子进程发送 SIGUSR2 信号给父进程kill(getppid(), SIGUSR2);exit(EXIT_SUCCESS);} else { // 父进程// 父进程发送 SIGUSR1 信号给子进程kill(cpid, SIGUSR1);// 父进程等待一段时间,让子进程处理信号sleep(1);// 父进程发送 SIGUSR2 信号给子进程kill(cpid, SIGUSR2);// 父进程等待子进程结束wait(NULL);}return 0;
}

信号示例流程解读:

设置信号处理函数:
使用 sigaction 函数设置信号处理函数 signal_handler,处理 SIGUSR1 和 SIGUSR2 信号。
创建子进程:
使用 fork 函数创建一个子进程。
父进程发送信号:
父进程使用 kill 函数发送 SIGUSR1 信号给子进程。
父进程等待一段时间,让子进程处理信号。
父进程再次使用 kill 函数发送 SIGUSR2 信号给子进程。
子进程发送信号:
子进程等待一段时间,让父进程先发送信号。
子进程使用 kill 函数发送 SIGUSR1 信号给父进程。
子进程等待一段时间,让父进程处理信号。
子进程再次使用 kill 函数发送 SIGUSR2 信号给父进程。
父进程等待子进程结束:
使用 wait 函数等待子进程结束。

信号示例执行效果

在这里插入图片描述

五、套接字(Sockets)

套接字是一种网络通信方式,允许不同主机上的进程进行通信。套接字可以用于本地进程间通信(通过Unix域套接字)和远程进程间通信(通过Internet域套接字)。

套接字示例代码:

以下是一个使用套接字在父进程和子进程之间进行通信的示例。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/wait.h> #define PORT 8080
#define BUFFER_SIZE 1024int main() {int server_fd, new_socket, valread;struct sockaddr_in address;int addrlen = sizeof(address);char buffer[BUFFER_SIZE] = {0};char *hello = "Hello from server";// 创建套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// 绑定套接字address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");close(server_fd);exit(EXIT_FAILURE);}// 监听套接字if (listen(server_fd, 3) < 0) {perror("listen");close(server_fd);exit(EXIT_FAILURE);}// 创建子进程pid_t cpid = fork();if (cpid == -1) { // fork 失败perror("fork");close(server_fd);exit(EXIT_FAILURE);} else if (cpid == 0) { // 子进程// 子进程作为客户端struct sockaddr_in serv_addr;int sock = 0;if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket");exit(EXIT_FAILURE);}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);  // 显式指定服务器 IP 地址// 连接到服务器if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("connect");close(sock);exit(EXIT_FAILURE);}// 发送消息send(sock, "Hello from client", strlen("Hello from client"), 0);// 接收消息valread = read(sock, buffer, BUFFER_SIZE);printf("Message received from server: %s\n", buffer);// 关闭套接字close(sock);exit(EXIT_SUCCESS);} else { // 父进程// 父进程作为服务器if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");close(server_fd);exit(EXIT_FAILURE);}// 接收消息valread = read(new_socket, buffer, BUFFER_SIZE);printf("Message received from client: %s\n", buffer);// 发送消息send(new_socket, hello, strlen(hello), 0);// 关闭套接字close(new_socket);close(server_fd);// 等待子进程结束wait(NULL);}return 0;
}

套接字示例流程解读:

1、创建套接字:父进程创建一个 TCP 套接字。

2、绑定套接字:父进程将套接字绑定到本地地址和端口。

3、监听套接字:父进程将套接字设置为监听状态,等待客户端连接。

4、创建子进程:父进程创建一个子进程。

5、子进程作为客户端:
子进程创建一个新的 TCP 套接字。
子进程连接到父进程的服务器。
子进程发送消息 “Hello from client” 到服务器。
子进程接收服务器的消息并打印。
子进程关闭套接字并退出。

6、父进程作为服务器:
父进程接受客户端的连接请求。
父进程接收客户端的消息并打印。
父进程发送消息 “Hello from server” 到客户端。
父进程关闭套接字并等待子进程结束。

套接字示例执行结果

在这里插入图片描述

六、信号量(Semaphores)

信号量是一种用于控制对共享资源访问的同步机制。它可以用于进程间的同步和互斥。

信号量示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>#define SEM_NAME "/my_semaphore"
#define SHARED_FILE "shared_file.txt"int main() {sem_t *sem;int fd;pid_t pid;// 创建信号量sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);if (sem == SEM_FAILED) {perror("sem_open");exit(EXIT_FAILURE);}// 创建共享文件fd = open(SHARED_FILE, O_CREAT | O_RDWR, 0666);if (fd == -1) {perror("open");sem_close(sem);sem_unlink(SEM_NAME);exit(EXIT_FAILURE);}close(fd);// 创建子进程pid = fork();if (pid == -1) {perror("fork");sem_close(sem);sem_unlink(SEM_NAME);exit(EXIT_FAILURE);} else if (pid == 0) { // 子进程// 子进程写入共享文件fd = open(SHARED_FILE, O_WRONLY);if (fd == -1) {perror("open");sem_close(sem);sem_unlink(SEM_NAME);exit(EXIT_FAILURE);}// 等待信号量if (sem_wait(sem) == -1) {perror("sem_wait");close(fd);sem_close(sem);sem_unlink(SEM_NAME);exit(EXIT_FAILURE);}// 写入消息const char *msg = "Hello from child";write(fd, msg, strlen(msg));printf("Child: Wrote message to shared file\n");// 释放信号量if (sem_post(sem) == -1) {perror("sem_post");close(fd);sem_close(sem);sem_unlink(SEM_NAME);exit(EXIT_FAILURE);}close(fd);exit(EXIT_SUCCESS);} else { // 父进程// 父进程读取共享文件fd = open(SHARED_FILE, O_RDONLY);if (fd == -1) {perror("open");sem_close(sem);sem_unlink(SEM_NAME);exit(EXIT_FAILURE);}// 等待信号量if (sem_wait(sem) == -1) {perror("sem_wait");close(fd);sem_close(sem);sem_unlink(SEM_NAME);exit(EXIT_FAILURE);}// 重置文件偏移量到文件开头lseek(fd, 0, SEEK_SET);// 读取消息char buffer[1024];ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);if (bytes_read == -1) {perror("read");close(fd);sem_close(sem);sem_unlink(SEM_NAME);exit(EXIT_FAILURE);}buffer[bytes_read] = '\0';printf("Parent: Read message from shared file: %s\n", buffer);// 释放信号量if (sem_post(sem) == -1) {perror("sem_post");close(fd);sem_close(sem);sem_unlink(SEM_NAME);exit(EXIT_FAILURE);}close(fd);// 等待子进程结束wait(NULL);// 关闭信号量sem_close(sem);sem_unlink(SEM_NAME);}return 0;
}

信号量示例流程解读:

1、创建信号量:使用 sem_open 函数创建一个命名信号量 SEM_NAME,初始值为 1。

2、创建共享文件:使用 open 函数创建一个共享文件 SHARED_FILE,如果文件已存在则打开它。

3、创建子进程:使用 fork 函数创建一个子进程。

4、子进程写入共享文件:
子进程打开共享文件,准备写入。
使用 sem_wait 函数等待信号量,确保只有一个进程可以访问共享文件。
写入消息 “Hello from child” 到共享文件。
使用 sem_post 函数释放信号量。
关闭文件并退出子进程。

5、父进程读取共享文件:
父进程打开共享文件,准备读取。
使用 sem_wait 函数等待信号量,确保只有一个进程可以访问共享文件。
重置文件偏移量到文件开头。
读取共享文件中的消息并打印。
使用 sem_post 函数释放信号量。
关闭文件,等待子进程结束,关闭信号量并删除信号量。

信号量示例执行结果

在这里插入图片描述

七、文件映射(Memory-Mapped Files)

文件映射允许将文件或文件的一部分映射到内存中,从而允许多个进程共享同一块内存区域。这在处理大文件时特别有用。

文件映射示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>#define SHARED_FILE "shared_file.txt"
#define MMAP_SIZE 1024int main() {int fd;pid_t pid;char *mapped_memory;// 创建共享文件fd = open(SHARED_FILE, O_CREAT | O_RDWR, 0666);if (fd == -1) {perror("open");exit(EXIT_FAILURE);}// 设置文件大小if (ftruncate(fd, MMAP_SIZE) == -1) {perror("ftruncate");close(fd);exit(EXIT_FAILURE);}// 映射文件到内存mapped_memory = mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (mapped_memory == MAP_FAILED) {perror("mmap");close(fd);exit(EXIT_FAILURE);}// 创建子进程pid = fork();if (pid == -1) {perror("fork");munmap(mapped_memory, MMAP_SIZE);close(fd);exit(EXIT_FAILURE);} else if (pid == 0) { // 子进程// 子进程写入共享内存const char *msg = "Hello from child";strcpy(mapped_memory, msg);printf("Child: Wrote message to shared memory: %s\n", mapped_memory);// 等待一段时间,让父进程有时间读取sleep(1);exit(EXIT_SUCCESS);} else { // 父进程// 父进程读取共享内存sleep(1); // 等待子进程写入printf("Parent: Read message from shared memory: %s\n", mapped_memory);// 等待子进程结束wait(NULL);// 取消内存映射if (munmap(mapped_memory, MMAP_SIZE) == -1) {perror("munmap");close(fd);exit(EXIT_FAILURE);}// 关闭文件close(fd);// 删除共享文件unlink(SHARED_FILE);}return 0;
}

文件映射示例流程解读:

1、创建共享文件:使用 open 和 ftruncate 函数创建并设置共享文件的大小。

2、映射文件到内存:使用 mmap 函数将文件映射到内存区域。

3、创建子进程:使用 fork 函数创建一个子进程。

4、子进程写入共享内存:子进程将消息写入共享内存区域,并打印写入的消息。

5、父进程读取共享内存:父进程读取共享内存区域中的消息并打印,等待子进程结束,取消内存映射,关闭文件并删除共享文件。

文件映射示例执行结果

在这里插入图片描述


总结

管道:适用于父子进程间的简单通信。

消息队列:适用于需要发送和接收消息的场景。

共享内存:适用于需要高效共享大量数据的场景。

信号:适用于异步事件的通知。

套接字:适用于网络通信和本地进程间通信。

信号量:适用于进程间的同步和互斥。

文件映射:适用于处理大文件和共享内存。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

分析redis实现分布式锁的思路

文章目录 1、基于redis实现分布式锁&#xff1a;利用key的唯一性1.1、独占排他1.2、死锁问题1.2.1、redis客户端程序获取了锁之后&#xff0c;服务器立马宕机&#xff0c;就会导致死锁。1.2.2、不可重入&#xff1a;可重入 1.3、原子性&#xff1a;加锁和过期之间&#xff1a;s…

【JavaEE】——线程的安全问题和解决方式

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 一&#xff1a;问题引入 二&#xff1a;问题深入 1&#xff1a;举例说明 2&#xff1a;图解双线程计算…

springboot数字化超市管理系统—计算机毕业设计源码34804

摘 要 在网络信息的时代&#xff0c;众多的软件被开发出来&#xff0c;给用户带来了很大的选择余地&#xff0c;而且人们越来越追求更个性的需求。在这种时代背景下&#xff0c;超市只能以用户为导向&#xff0c;按品种小批量组织生产&#xff0c;以产品的持续创新作为超市最重…

ONES 与华为云深度合作,共同打造企业智能研发管理平台

9月20日&#xff0c;在华为全联接大会&#xff08;HUAWEI CONNECT 2024&#xff09;上&#xff0c;深圳复临科技有限公司&#xff08;以下简称“ONES”&#xff09;与华为云计算技术有限公司&#xff08;以下简称“华为云”&#xff09;正式签署合作协议&#xff0c;双方将在企…

Python | Leetcode Python题解之第421题数组中两个数的最大异或值

题目&#xff1a; 题解&#xff1a; class Trie:def __init__(self):# 左子树指向表示 0 的子节点self.left None# 右子树指向表示 1 的子节点self.right Noneclass Solution:def findMaximumXOR(self, nums: List[int]) -> int:# 字典树的根节点root Trie()# 最高位的二…

【图灵完备 Turing Complete】游戏经验攻略分享 Part.6 处理器架构2 函数

新的架构来了&#xff0c;本游戏的最后一个攻略分享&#xff0c;最后汇编部分无非是对于操作码的熟练&#xff0c;硬件没有问题&#xff0c;那么也就无关痛痒了。 汇编实现&#xff0c;两数相或和两数相与非一起相与即可。 八位异或器&#xff0c;整就完事了。 有手就行。 利…

十七、RC振荡电路

振荡电路 1、振荡电路的组成、作用、起振的相位条件以及振荡电路起振和平衡幅度条件&#xff0c; 2、RC电路阻抗与频率、相位与频率的关系曲线; 3、RC振荡电路的相位条件分析和振荡频率

秩一的等价转化

Lemma 2. For a positive semi-definite Hermitian matrix A ∈ C M M \mathbf{A}\in\mathbb{C}^{M\times M} A∈CMM, the condition Rank ( A ) 1 \left(\mathbf{A}\right)1 (A)1 is equivalent to t h e following conditions the\textit{ following conditions} the fol…

JavaWeb 实验一

实验一 环境配置和Web工程的创建 目的&#xff1a; 掌握Java Web编程环境的配置创建简单的Web工程&#xff0c;并了解Web工程下各目录的作用掌握部署、运行Web工程的流程 实验过程&#xff1a; 一、完成如下要求。 安装并设置JDK 1.8、Tomcat 9.0&#xff08;tomcat和jdk版…

PDF转JPG神器!一键转换,轻松搞定文档分享难题

亲爱的朋友们&#xff0c;你是不是也常常被PDF文件格式所困扰&#xff1f;特别是当你想要将PDF文件转换为JPG格式时&#xff0c;是否觉得有些头大呢&#xff1f;别担心&#xff0c;今天我将向你推荐五款非常棒的PDF转JPG工具&#xff0c;它们绝对能让你的转换过程轻松愉快&…

暴力枚举算法

《啊哈&#xff01;算法》学习笔记 本博客的题目仅用暴力枚举&#xff0c;并不一定是最好的解法&#xff0c;主要是了解枚举算法 例题一&#xff1a;两方框奥数 在两个方框内填入相同的数字使得等式成立&#xff1a; 代码如下&#xff1a; for(i1;i<9;i) {if((i*103)*652…

数据结构---二叉搜索树(二叉排序树)

什么是二叉排序树 二叉搜索树又是二叉排序树&#xff0c;当我们的是一颗空树或者具有以下性质时&#xff1a; 左子树不为空&#xff0c;左子树上的值都小于我们的根节点上的值。右子树不为空时&#xff0c;右子树上的值都大于我们的根节点上的值左右子树都是二叉搜索树&#…

Java异常架构与异常关键字

1. Java异常简介 Java 异常是 Java 提供的一种识别及响应错误的一致性机制。 Java 异常机制可以使程序中异常处理代码和正常业务代码分离&#xff0c;保证程序代码更加优雅&#xff0c;并提高程 序健壮性。在有效使用异常的情况下&#xff0c;异常能清晰的回答 what, where,…

2023北华大学程序设计新生赛部分题解

时光如流水般逝去&#xff0c;我已在校园中奋战大二&#xff01;(≧▽≦) 今天&#xff0c;静静回顾去年的新生赛&#xff0c;心中涌起无尽感慨&#xff0c;仿佛那段青春岁月如烟花般绚烂。✧&#xff61;(≧▽≦)&#xff61;✧ 青春就像一场燃烧的盛宴&#xff0c;激情澎湃&…

《高等代数》线性相关和线性无关(应用)

说明&#xff1a;此文章用于本人复习巩固&#xff0c;如果也能帮到大家那就更加有意义了。 注&#xff1a;1&#xff09;线性相关和线性无关的证明方法中较为常用的方法是利用秩和定义来证明。 2&#xff09;此外&#xff0c;线性相关和线性无关的证明常常也会用到反证法。 3&…

2.5 数据库索引机制

我们往数据表里面保存数据记录越来越多&#xff0c;一旦达到上千万条&#xff0c;那怎么提高检索速度就需要认真考虑了。我们打开手机上的APP都希望能快些加载出内容&#xff0c;这里的因素有很多&#xff0c;但是如何减少数据查找的时间是其中的重要一环。索引机制就是提升数据…

怎么给视频加字幕?6种给视频加字幕最简单的方法,不怕你学不会!

在这个快节奏的时代&#xff0c;越来越多的人会在公共场所观看视频&#xff0c;但为了不影响其它人&#xff0c;大多数人往往会将声音关闭。统计数据显示&#xff0c;高达69%的人在这样的环境中会静音观看视频&#xff0c;而有字幕的情况下&#xff0c;80%的人更倾向于完整观看…

刷题训练之栈

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握字符串算法。 > 毒鸡汤&#xff1a;学习&#xff0c;学习&#xff0c;再学习 ! 学&#xff0c;然后知不足。 > 专栏选自&#xff1a;刷题…

C++之spring

C之spring string类对象的访问及遍历操作 operator[] 返回pos位置的字符&#xff0c;const string类对象调用 这是一个既可以写也可以读的库函数&#xff0c;const修饰的内容是不可以更改的&#xff0c;所以是读 C类与对象里要想普通对象和const修饰的对象同时重载 第二种访…

2024华为杯研究生数学建模,代码思路和参考文章

F题X射线脉冲星光子到达时间建模&#xff0c; E题高速公路应急车道紧急启用模型&#xff0c; D题大数据驱动的地理综合问題&#xff0c; C题数据驱动下磁性元件的磁芯损耗建模&#xff0c; B题W LAN 组网中网络吞吐量建模&#xff0c; A题风电场有功功率优化分配&#xff…