操作系统:进程间通信方式详解(下:消息队列、信号量、共享内存、套接字)

每日一问:操作系统:进程间通信方式详解(下:消息队列、信号量、共享内存、套接字)

进程间通信(Inter-Process Communication,IPC)是操作系统中实现不同进程之间数据交换和协作的关键机制。本文详细介绍了几种常用的 IPC 方式,包括消息队列、信号量、共享内存和套接字。每种通信方式都有其独特的应用场景和优势,而现有的介绍往往局限于概念的介绍,本文则结合实际应用,通过极为详细的可以运行的 C++ 和 Java 示例代码,帮助读者理解这些机制的实现原理和应用场景。 对于无名管道、有名管道、高级管道,则可见操作系统:进程间通信方式详解(上:无名管道、有名管道、高级管道)。


文章目录

  • 每日一问:操作系统:进程间通信方式详解(下:消息队列、信号量、共享内存、套接字)
    • 一、进程间通信概述
    • 二、消息队列(Message Queue)
      • 2.1 消息队列的定义与特点
      • 2.2 消息队列的C++示例代码
      • 2.3 消息队列的Java示例代码
    • 三、信号量(Semaphore)
      • 3.1 信号量的定义与特点
      • 3.2 信号量的C++示例代码
      • 3.3 信号量的Java示例代码
    • 四、共享内存(Shared Memory)
      • 4.1 共享内存的定义与特点
      • 4.2 共享内存的C++示例代码
      • 4.3 共享内存的Java示例代码
    • 五、套接字(Socket)
      • 5.1 套接字的定义与特点
      • 5.2 套接字的实现
        • C++ 示例代码(TCP 套接字通信)
        • Java 示例代码(TCP 套接字通信)
    • 六、总结(前面可以不看,这里表格总结必看)


本文深入讲解了消息队列、信号量、共享内存和套接字的定义、特点及实际应用,结合代码示例展示了这些 IPC 方式在进程间数据传输与同步中的应用。文章适合对进程间通信感兴趣的初学者和开发人员,通过示例代码掌握 IPC 机制的具体实现。


一、进程间通信概述

进程是操作系统的基本执行单位,每个进程有独立的内存空间。由于这种独立性,进程之间无法直接访问对方的数据,进程间通信(IPC)机制因此应运而生。常见的 IPC 方式包括无名管道、有名管道、消息队列、信号量、共享内存和套接字等。这些方式在数据传输效率、同步机制和复杂度上各不相同,适用于不同的应用场景。在接下来的章节,将介绍消息队列、信号量、共享内存和套接字,对于无名管道、有名管道、高级管道,则可见操作系统:进程间通信方式详解(上:无名管道、有名管道、高级管道)。

二、消息队列(Message Queue)

2.1 消息队列的定义与特点

消息队列是一种基于消息传递的通信机制,允许进程通过消息队列发送和接收消息。消息队列支持异步通信,发送方和接收方不需要同时工作。消息队列的特点是消息可以按优先级和顺序存储,便于进程之间有序交换数据。

2.2 消息队列的C++示例代码

以下是一个消息队列的 C++ 示例代码,通过 msggetmsgsndmsgrcv 系统调用创建和操作消息队列:

#include <iostream>  // 标准输入输出库
#include <sys/ipc.h>  // IPC 机制相关函数
#include <sys/msg.h>  // 消息队列相关函数
#include <cstring>  // 字符串操作库// 定义消息结构体
struct msg_buffer {long msg_type;  // 消息类型,必须为正整数char msg_text[100];  // 消息内容
};int main() {key_t key;int msgid;msg_buffer message;// 使用 ftok 生成消息队列的唯一键key = ftok("progfile", 65);  // "progfile" 文件名,65 是一个任意数值// 使用 msgget 创建消息队列,如果不存在则创建,权限设置为 0666msgid = msgget(key, 0666 | IPC_CREAT);message.msg_type = 1;  // 设置消息类型为 1// 写入消息到消息队列std::cout << "Write Message: ";std::cin.getline(message.msg_text, sizeof(message.msg_text));  // 从控制台读取消息msgsnd(msgid, &message, sizeof(message), 0);  // 发送消息到队列// 读取消息队列msgrcv(msgid, &message, sizeof(message), 1, 0);  // 接收消息类型为 1 的消息std::cout << "Received Message: " << message.msg_text << std::endl;  // 打印接收到的消息// 删除消息队列msgctl(msgid, IPC_RMID, NULL);  // 删除消息队列,清理资源return 0;
}

解释

  1. ftok():生成唯一的键值,用于识别消息队列。
  2. msgget():创建一个新的消息队列或获取一个已存在的消息队列。
  3. msgsnd():向消息队列发送消息。
  4. msgrcv():从消息队列接收消息。
  5. msgctl():控制消息队列,如删除队列。

2.3 消息队列的Java示例代码

Java 没有直接的消息队列实现,可以通过 BlockingQueue 类进行模拟:

import java.util.concurrent.BlockingQueue;  // 导入 BlockingQueue 接口,用于实现阻塞队列
import java.util.concurrent.LinkedBlockingQueue;  // 导入 LinkedBlockingQueue 类,实现线程安全的阻塞队列public class MessageQueueExample {// 创建一个阻塞队列用于模拟消息队列private static BlockingQueue<String> queue = new LinkedBlockingQueue<>();public static void main(String[] args) throws InterruptedException {// 创建发送线程Thread sender = new Thread(() -> {try {queue.put("Hello from sender!");  // 向队列中放入消息} catch (InterruptedException e) {e.printStackTrace();  // 捕获并打印异常}});// 创建接收线程Thread receiver = new Thread(() -> {try {String message = queue.take();  // 从队列中取出消息System.out.println("Received: " + message);  // 输出接收到的消息} catch (InterruptedException e) {e.printStackTrace();  // 捕获并打印异常}});sender.start();  // 启动发送线程receiver.start();  // 启动接收线程sender.join();  // 等待发送线程结束receiver.join();  // 等待接收线程结束}
}

解释

  1. BlockingQueue:Java 中用于线程间通信的阻塞队列,模拟消息队列的异步特性。
  2. put()take():分别用于将消息放入队列和从队列中取出消息,实现发送和接收操作。

三、信号量(Semaphore)

3.1 信号量的定义与特点

信号量是一种用于进程间同步的计数器机制,可以控制多个进程对共享资源的访问。信号量经常与共享内存结合使用,解决并发访问问题,确保资源不会被多个进程同时访问而导致数据冲突。

3.2 信号量的C++示例代码

以下是一个简单的 C++ 信号量示例,演示如何使用信号量控制线程对临界区的访问:

#include <iostream>  // 标准输入输出库
#include <pthread.h>  // POSIX 线程库
#include <semaphore.h>  // 信号量库sem_t semaphore;  // 定义信号量// 线程执行的任务函数
void* task(void* arg) {sem_wait(&semaphore);  // 尝试获取信号量,信号量值减 1std::cout << "Entered critical section" << std::endl;  // 打印消息表示进入临界区sem_post(&semaphore);  // 释放信号量,信号量值加 1return NULL;
}int main() {pthread_t t1, t2;  // 定义两个线程sem_init(&semaphore, 0, 1);  // 初始化信号量,0 表示信号量用于线程间同步,初始值为 1// 创建两个线程执行任务pthread_create(&t1, NULL, task, NULL);pthread_create(&t2, NULL, task, NULL);// 等待两个线程执行完毕pthread_join(t1, NULL);pthread_join(t2, NULL);sem_destroy(&semaphore);  // 销毁信号量,释放资源return 0;
}

解释

  1. sem_init():初始化信号量,指定信号量初始值。
  2. sem_wait():等待信号量,可进入临界区时信号量值减 1。
  3. sem_post():释放信号量,信号量值加 1。
  4. sem_destroy():销毁信号量,清理资源。

3.3 信号量的Java示例代码

Java 通过 java.util.concurrent.Semaphore 类实现信号量控制:

import java.util.concurrent.Semaphore;  // 导入 Semaphore 类public class SemaphoreExample {private static Semaphore semaphore = new Semaphore(1);  // 创建信号量,初始值为 1public static void main(String[] args) {// 定义线程任务Runnable task = () -> {try {semaphore.acquire();  // 获取信号量,阻塞直到信号量可用System.out.println("Entered critical section");  // 打印进入临界区的消息semaphore.release();  // 释放信号量} catch (InterruptedException e) {e.printStackTrace();  // 捕获并打印异常}};// 创建并启动两个线程Thread t1 = new Thread(task);Thread t2 = new Thread(task);t1.start();t2.start();}
}

解释

  1. acquire():尝试获取信号量,信号量不足时阻塞。
  2. release():释放信号量,允许其他线程进入临界区。

四、共享内存(Shared Memory)

4.1 共享内存的定义与特点

共享内存是最直接的进程间通信方式,通过多个进程共享一块内存区域来进行数据交换。共享内存提供了最快的通信速度,但需要借助同步机制来防止数据冲突。

4.2 共享内存的C++示例代码

以下代码展示了共享内存的使用方法,通过 shmgetshmat 系统调用来创建和连接共享内存:

#include <iostream>  // 标准输入输出库
#include <sys/ipc.h>  // IPC 机制相关函数
#include <sys/shm.h>  // 共享内存相关函数
#include <cstring>  // 字符串操作库int main() {// 创建共享内存键值,"shmfile" 是用于生成键值的路径,65 是任意选定的整数key_t key = ftok("shmfile", 65);// 创建共享内存,大小为 1024 字节,权限为 0666,若不存在则创建int shmid = shmget(key, 1024, 0666 | IPC_CREAT);// 连接到共享内存,返回一个指向共享内存的指针char *str = (char*) shmat(shmid, (void*)0, 0);strcpy(str, "Hello Shared Memory!");  // 向共享内存写入数据std::cout << "Data written in memory: " << str << std::endl;  // 输出写入的数据shmdt(str);  // 断开共享内存连接shmctl(shmid, IPC_RMID, NULL);  // 删除共享内存,清理资源return 0;
}

解释

  1. shmget():创建共享内存段,指定大小和权限。
  2. shmat():将共享内存附加到进程地址空间,返回指向共享内存的指针。
  3. shmdt():将共享内存从当前进程地址空间分离。
  4. shmctl():控制共享内存,包括删除共享内存段。

4.3 共享内存的Java示例代码

Java 通过 MappedByteBuffer 类实现类似共享内存的功能:

import java.io.RandomAccessFile;  // 导入 RandomAccessFile 类,用于文件读写
import java.nio.MappedByteBuffer;  // 导入 MappedByteBuffer 类,用于内存映射
import java.nio.channels.FileChannel;  // 导入 FileChannel 类,用于文件通道操作public class SharedMemoryExample {public static void main(String[] args) throws Exception {// 创建或打开文件 "shared_memory.bin",读写模式RandomAccessFile file = new RandomAccessFile("shared_memory.bin", "rw");// 将文件映射到内存,映射模式为读写,大小为 1024 字节MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1024);buffer.put("Hello Shared Memory!".getBytes());  // 将数据写入内存映射buffer.flip();  // 重置缓冲区位置以便读取byte[] data = new byte[buffer.remaining()];  // 创建字节数组保存读取的数据buffer.get(data);  // 从缓冲区读取数据System.out.println("Data read from memory: " + new String(data));  // 输出读取的数据file.close();  // 关闭文件}
}

解释

  1. MappedByteBuffer:将文件的某一部分映射到内存,允许直接对文件数据进行读写。
  2. map():将文件通道中的数据映射到内存区域。
  3. flip():重置缓冲区位置,以便后续的读取操作。

五、套接字(Socket)

5.1 套接字的定义与特点

套接字(Socket)是一种支持本地和网络通信的进程间通信方式,可以在本地进程间或跨网络的不同计算机之间进行双向通信。套接字支持 TCP(可靠传输)和 UDP(不可靠但高效)两种协议。

5.2 套接字的实现

套接字是通信端点,通过绑定 IP 地址和端口号来进行数据交换。

C++ 示例代码(TCP 套接字通信)
#include <iostream>  // 标准输入输出库
#include <sys/socket.h>  // 套接字库
#include <arpa/inet.h>  // 地址转换库
#include <unistd.h>  // POSIX 操作库int main() {int server_fd, new_socket;  // 定义服务器套接字和新连接套接字struct sockaddr_in address;  // 定义地址结构体int opt = 1;int addrlen = sizeof(address);char buffer[1024] = {0};  // 定义缓冲区用于接收数据const char *hello = "Hello from server";  // 定义发送给客户端的消息// 创建套接字,使用 IPv4 地址族,TCP 流式套接字server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd == 0) {  // 检查套接字创建是否成功perror("socket failed");return 1;}// 设置套接字选项,允许地址和端口重用setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));// 绑定套接字到指定的 IP 地址和端口address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;  // 使用本地所有可用的 IP 地址address.sin_port = htons(8080);  // 端口号 8080if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");return 1;}// 监听端口,最大等待连接数为 3if (listen(server_fd, 3) < 0) {perror("listen failed");return 1;}// 接受客户端连接new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen);if (new_socket < 0) {perror("accept failed");return 1;}// 读取客户端消息read(new_socket, buffer, 1024);std::cout << "Message from client: " << buffer << std::endl;// 发送回复给客户端send(new_socket, hello, strlen(hello), 0);std::cout << "Hello message sent" << std::endl;// 关闭套接字close(new_socket);close(server_fd);return 0;
}
Java 示例代码(TCP 套接字通信)
import java.io.*;  // 导入输入输出类
import java.net.*;  // 导入网络类public class SocketServer {public static void main(String[] args) {try (ServerSocket serverSocket = new ServerSocket(8080)) {  // 创建服务器套接字绑定到端口 8080System.out.println("Server started, waiting for connection...");// 等待客户端连接Socket socket = serverSocket.accept();System.out.println("Client connected.");// 创建输入输出流BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter output = new PrintWriter(socket.getOutputStream(), true);// 读取客户端消息String clientMessage = input.readLine();System.out.println("Received from client: " + clientMessage);// 回复客户端output.println("Hello from server!");// 关闭连接socket.close();} catch (IOException e) {e.printStackTrace();}}
}

解释

  1. ServerSocket:服务器端套接字,监听指定端口。
  2. accept():等待客户端连接,建立连接后返回客户端的套接字。
  3. BufferedReaderPrintWriter:用于处理输入输出流,读取客户端发送的数据并进行响应。

六、总结(前面可以不看,这里表格总结必看)

进程间通信(IPC)是操作系统中实现进程间数据交换和同步的关键技术。不同的 IPC 方式在性能、适用场景、易用性上各有特点:

通信方式定义特点应用场景
无名管道单向数据传输,父子进程间简单、只支持亲缘进程父子进程间数据传输
有名管道有名且持久,支持无亲缘进程双向、需文件系统支持任意进程间的数据传输
高级管道通过子进程执行命令并传输数据创建灵活,可执行命令结果执行系统命令,获取输出
消息队列基于消息的通信异步、按优先级排序异步任务处理
信号量计数器机制,控制资源访问同步、解决并发冲突多进程资源访问控制
共享内存共享内存区域快速传输数据高速、需同步机制需高效通信的场景
套接字本地和网络通信支持双向、网络和本地通信网络应用、跨主机进程间通信

下面给出更复杂版本的对比表格:

通信方式数据传输方向是否支持无亲缘关系进程同步与异步速度数据持久性编程复杂性典型应用场景
无名管道单向同步中等不持久父子进程间简单数据传输
有名管道双向同步中等不持久无亲缘关系进程间数据传输
高级管道单向同步中等不持久父子进程间调用系统命令或可执行程序
消息队列单向异步中等不持久多个进程间复杂数据交换
信号量N/A同步N/AN/A进程/线程同步,解决资源争用问题
共享内存双向同步(需同步机制)不持久大量数据的快速读写,需同步控制
套接字双向是(支持网络通信)同步/异步视网络环境而定不持久本地或网络进程间的复杂数据通信

通过正确选择 IPC 机制,开发者可以有效实现进程间的数据交换和同步,提升系统的响应速度和稳定性。根据实际需求,选择合适的进程间通信方式,可以最大限度地提高应用程序的性能和可靠性。

✨ 我是专业牛,一个渴望成为大牛🏆的985硕士🎓,热衷于分享知识📚,帮助他人解决问题💡,为大家提供科研、竞赛等方面的建议和指导🎯。无论是科研项目🛠️、竞赛🏅,还是图像🖼️、通信📡、计算机💻领域的论文辅导📑,我都以诚信为本🛡️,质量为先!🤝

如果你觉得这篇文章对你有所帮助,别忘了点赞👍、收藏📌和关注🔔!你的支持是我继续分享知识的动力🚀!✨ 如果你有任何问题或需要帮助,随时留言📬或私信📲,我都会乐意解答!😊

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

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

相关文章

【有啥问啥】深度剖析:大模型AI时代下的推理路径创新应用方法论

深度剖析&#xff1a;大模型AI时代下的推理路径创新应用方法论 随着大规模预训练模型&#xff08;Large Pretrained Models, LPMs&#xff09;和生成式人工智能的迅速发展&#xff0c;AI 在多领域的推理能力大幅提升&#xff0c;尤其是在自然语言处理、计算机视觉和自动决策领…

程序员如何保持与提升核心竞争力

一、引言  随着AIGC&#xff08;人工智能生成内容&#xff09;的快速发展&#xff0c;如chatgpt、midjourney、claude等大语言模型的涌现&#xff0c;AI辅助编程工具正逐渐成为程序员日常工作的得力助手。这一变革不仅对程序员的工作方式产生了深刻影响&#xff0c;也引发了关…

Kafka 下载安装及使用总结

1. 下载安装 官网下载地址&#xff1a;Apache Kafka 下载对应的文件 上传到服务器上&#xff0c;解压 tar -xzf kafka_2.13-3.7.0.tgz目录结果如下 ├── bin │ └── windows ├── config │ └── kraft ├── libs ├── licenses └── site-docs官方文档…

动态数据源多种实现方式及对比详细介绍

文章目录 动态数据源实现方式1. 概述2. 动态数据源实现方式2.1 基于 AbstractRoutingDataSource 实现动态数据源2.2 基于 Spring AOP 实现动态数据源2.3 基于 TransactionManager 实现动态数据源2.4 通过数据库中间件实现动态数据源&#xff08;ShardingSphere、MyCAT&#xff…

探索 Go 语言 container 包:强大容器的魔法世界

《探索 Go 语言 container 包:强大容器的魔法世界》 在 Go 语言的世界里,container包就像是一个神奇的宝库,里面藏着各种强大的容器,为开发者提供了高效的数据存储和操作方式。让我们一起揭开这个宝库的神秘面纱,探索container包中的那些容器。 一、container包简介 co…

将成功请求的数据 放入apipost接口测试工具,发送给后端后,部分符号丢失

将成功请求的数据 放入apipost接口测试工具&#xff0c;发送给后端后&#xff0c;部分符号丢失 apipost、接口测试、符号、丢失、错乱、变成空格背景 做CA对接&#xff0c;保存CA系统的校验数据&#xff0c;需要模仿前端请求调起接口&#xff0c;以便测试功能完整性。 问题描…

MySQL:事务隔离级别

SQL 标准定义了四个隔离级别&#xff1a; READ-UNCOMMITTED(读取未提交) &#xff1a;最低的隔离级别&#xff0c;允许读取尚未提交的数据变更&#xff0c;可能会导致脏读、幻读或不可重复读。READ-COMMITTED(读取已提交) &#xff1a;允许读取并发事务已经提交的数据&#xf…

Flink Task 日志文件隔离

Flink Task 日志文件隔离 任务在启动时会先通过 MdcUtils 启动一个 slf4j 的 MDC 环境&#xff0c;然后将 jobId 添加到 slf4j 的 MDC 容器中&#xff0c;随后任务输出的日志都将附带 joid。 MDC 介绍如下&#xff1a; MDC ( Mapped Diagnostic Contexts )&#xff0c;它是一个…

深度学习:(六)激活函数的选择与介绍

激活函数 之前使用的 a σ ( z ) a\sigma(z) aσ(z) &#xff0c;其中 σ ( ) \sigma(~) σ( ) 便是激活函数。 在神经网络中&#xff0c;不同层的激活函数可以不同。 在学习中&#xff0c;一般以 g ( z ) g(z) g(z) 来表示激活函数。 为什么需要(线性)激活函数&#xff…

K8s容器运行时,移除Dockershim后存在哪些疑惑?

K8s容器运行时&#xff0c;移除Dockershim后存在哪些疑惑&#xff1f; 大家好&#xff0c;我是秋意零。 K8s版本截止目前&#xff08;24/09&#xff09;已经发布到了1.31.x版本。早在K8s版本从1.24.x起&#xff08;22/05&#xff09;&#xff0c;默认的容器运行时就不再是Doc…

暑假考研集训营游记

文章目录 摘要&#xff1a;1.对各大辅导机构考研封闭集训营的一些个人看法&#xff1a;2.对于考研原因一些感想&#xff1a;结语 摘要&#xff1a; Ashy在暑假的时候参加了所在辅导班的为期一个月的考研封闭集训营&#xff0c;有了一些全新的感悟&#xff0c;略作记录。 1.对…

【SpringBoot】97、SpringBoot中使用EasyExcel导出/导入数据

1、EasyExcel Java 解析、生成 Excel 比较有名的框架有 Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi 有一套 SAX 模式的 API 可以一定程度的解决一些内存溢出的问题,但 POI 还是有一些缺陷,比如 07 版 Excel 解压缩以及解压后存储都是在内存中完成的,…

linux-系统备份与恢复-系统恢复

Linux 系统备份与恢复&#xff1a;系统恢复 1. 概述 Linux 系统的恢复是系统管理的重要组成部分&#xff0c;它指的是在系统崩溃、硬件故障、误操作或安全问题后&#xff0c;恢复系统到可用状态的过程。良好的系统恢复计划可以有效避免数据丢失和业务中断&#xff0c;并确保系…

ESP32配网接入Wifi

1 ESP32的两种模式 AP模式:ESP32可以作为热点,手机和电脑等设备接入使用。 STA模式:ESP32可以作为作为客户端接入其他网络中。 2 流程 step1: ESP32上电后进入STA模式,尝试看能够接入网络 step2: 如何连接成功,则正常运行。如何连接超时,则自动进入AP模式,设置AP热点…

算法之搜索--最长公共子序列LCS

最长公共子序列&#xff08;longest common sequence&#xff09;:可以不连续 最长公共子串&#xff08;longest common substring&#xff09;&#xff1a;连续 demo for (int i 1;i<lena;i){for (int j 1;j<lenb;j){if(a[i-1]b[j-1]){dp[i][j]dp[i-1][j-1]1;}el…

Qt (17)【Qt 文件操作 读写保存】

阅读导航 引言一、Qt文件概述二、输入输出设备类三、文件读写类四、文件和目录信息类五、自定义“记事本” 引言 在上一篇文章中&#xff0c;我们学习了Qt的事件处理机制&#xff0c;知道了如何响应用户的操作。但应用程序常常还需要处理文件&#xff0c;比如读写数据。所以&a…

python爬虫初体验(一)

文章目录 1. 什么是爬虫&#xff1f;2. 为什么选择 Python&#xff1f;3. 爬虫小案例3.1 安装python3.2 安装依赖3.3 requests请求设置3.4 完整代码 4. 总结 1. 什么是爬虫&#xff1f; 爬虫&#xff08;Web Scraping&#xff09;是一种从网站自动提取数据的技术。简单来说&am…

指针修仙之实现qsort

文章目录 回调函数什么是回调函数回调函数的作用 库函数qsort使用qsort函数排序整形使用qsort函数排序结构体 qsort函数模拟实现说明源码and说明 回调函数 什么是回调函数 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数…

Sigmoid引发的梯度消失爆炸及ReLU引起的神经元参数失效问题思考

Sigmoid和ReLU激活函数思考&#xff09; 引文Sigmoid函数梯度消失问题梯度爆炸问题解决方案 ReLU函数简化模型示例场景设定前向传播对反向传播的影响总结 内容精简版 引文 梯度消失和梯度爆炸是神经网络训练中常见的两个问题&#xff0c;特别是在使用Sigmoid激活函数时。这些问…

后端-navicat查找语句(单表与多表)

表格字段设置如图 语句&#xff1a; 1.输出 1.输出name和age列 SELECT name,age from student 1.2.全部输出 select * from student 2.where子语句 1.运算符&#xff1a; 等于 >大于 >大于等于 <小于 <小于等于 ! <>不等于 select * from stude…