linux的信号量初识
Linux下的信号量(Semaphore)深度解析
在多线程或多进程并发编程的领域中,确保对共享资源的安全访问和协调不同执行单元的同步至关重要。信号量(Semaphore)作为经典的同步原语之一,在 Linux 系统中扮演着核心角色。本文将深入探讨 Linux 环境下 POSIX 信号量的概念、工作原理、API 使用、示例代码、流程图及注意事项。
1. 什么是信号量?
信号量是由荷兰计算机科学家艾兹格·迪科斯彻(Edsger Dijkstra)在 1965 年左右提出的一个同步机制。本质上,信号量是一个非负整数计数器,它被用于控制对一组共享资源的访问。它主要支持两种原子操作:
- P 操作 (Proberen - 测试/尝试): 也称为
wait()
,down()
,acquire()
。此操作会检查信号量的值。- 如果信号量的值大于 0,则将其减 1,进程/线程继续执行。
- 如果信号量的值等于 0,则进程/线程会被阻塞(放入等待队列),直到信号量的值变为大于 0。
- V 操作 (Verhogen - 增加): 也称为
signal()
,up()
,post()
,release()
。此操作会将信号量的值加 1。- 如果此时有其他进程/线程因等待该信号量而被阻塞,则系统会唤醒其中一个(或多个,取决于实现)等待的进程/线程。
核心思想: 信号量的值代表了当前可用资源的数量。当一个进程/线程需要使用资源时,它执行 P 操作;当它释放资源时,执行 V 操作。
类比:
- 计数信号量 (Counting Semaphore): 想象一个有 N 个停车位的停车场。信号量的初始值是 N。每当一辆车进入,信号量减 1 (P 操作)。当车位满 (信号量为 0) 时,新来的车必须等待。每当一辆车离开,信号量加 1 (V 操作),并可能通知等待的车辆有空位了。
- 二值信号量 (Binary Semaphore): 停车场只有一个车位 (N=1)。信号量的值只能是 0 或 1。这常被用作互斥锁 (Mutex),确保同一时间只有一个进程/线程能访问某个临界区。
2. Linux 中的信号量类型
Linux 主要支持两种信号量实现:
- System V 信号量: 这是较老的一套 IPC (Inter-Process Communication) 机制的一部分(还包括 System V 消息队列和共享内存)。它功能强大但 API 相对复杂,信号量通常是内核持久的,需要显式删除。相关函数有
semget()
,semop()
,semctl()
。 - POSIX 信号量: 这是 POSIX 标准定义的一套接口,通常更推荐在新代码中使用。它提供了更简洁、更易于使用的 API。POSIX 信号量可以是命名信号量(可在不相关的进程间共享,通过名字访问,如
/mysemaphore
)或未命名信号量(通常在同一进程的线程间或父子进程间共享,存在于内存中)。
本文将重点关注更常用且推荐的 POSIX 未命名信号量。
3. POSIX 信号量核心 API (C/C++)
使用 POSIX 信号量需要包含头文件 <semaphore.h>
。
3.1 sem_init()
- 初始化未命名信号量
#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);
功能: 初始化位于 sem 指向地址的未命名信号量。
参数:
sem_t *sem
: 指向要初始化的信号量对象的指针。sem_t
是信号量类型。int pshared
: 控制信号量的共享范围。0
: 信号量在当前进程的线程间共享。信号量对象sem
应位于所有线程都能访问的内存区域(如全局变量、堆内存)。- 非
0
: 信号量在进程间共享。信号量对象sem
必须位于共享内存区域(例如使用mmap
创建的共享内存段)。
unsigned int value
: 信号量的初始值。对于二值信号量(用作锁),通常初始化为 1;对于计数信号量,根据可用资源数量初始化。
返回值:
- 成功: 返回 0。
- 失败: 返回 -1,并设置
errno
。常见的errno
包括EINVAL
(value 超过SEM_VALUE_MAX
),ENOSYS
(不支持进程间共享)。
3.2 sem_destroy()
- 销毁未命名信号量
#include <semaphore.h>int sem_destroy(sem_t *sem);
功能: 销毁由 sem_init()
初始化的未命名信号量 sem
。销毁一个正在被其他线程等待的信号量会导致未定义行为。只有在确认没有线程再使用该信号量后才能销毁。
参数:
sem_t *sem
: 指向要销毁的信号量对象的指针。
返回值:
- 成功: 返回 0。
- 失败: 返回 -1,并设置
errno
(如EINVAL
表示sem
不是一个有效的信号量)。
3.3 sem_wait()
- 等待(P 操作/减 1)
#include <semaphore.h>int sem_wait(sem_t *sem);
功能: 对信号量 sem
执行 P 操作(尝试减 1)。
- 如果信号量的值大于 0,则原子地将其减 1,函数立即返回。
- 如果信号量的值等于 0,则调用线程/进程将被阻塞,直到信号量的值大于 0(通常是另一个线程/进程调用
sem_post()
之后)或收到一个信号。
参数:
sem_t *sem
: 指向要操作的信号量对象的指针。
返回值:
- 成功: 返回 0。
- 失败: 返回 -1,并设置
errno
。EINVAL
:sem
不是一个有效的信号量。EINTR
: 操作被信号中断。应用程序通常需要检查errno
并重新尝试sem_wait()
。
3.4 sem_trywait()
- 非阻塞等待
#include <semaphore.h>int sem_trywait(sem_t *sem);
功能: sem_wait()
的非阻塞版本。
- 如果信号量的值大于 0,则原子地将其减 1,函数立即返回 0。
- 如果信号量的值等于 0,则函数立即返回 -1,并将
errno
设置为EAGAIN
,调用线程不会被阻塞。
参数:
sem_t *sem
: 指向要操作的信号量对象的指针。
返回值:
- 成功 (信号量减 1): 返回 0。
- 失败: 返回 -1,并设置
errno
。EAGAIN
: 信号量当前为 0,无法立即减 1。EINVAL
:sem
不是一个有效的信号量。
3.5 sem_timedwait()
- 带超时的等待
#include <semaphore.h>
#include <time.h>int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
功能: 类似 sem_wait()
,但带有超时限制。
- 如果信号量的值大于 0,则原子地将其减 1,函数立即返回 0。
- 如果信号量的值等于 0,则线程阻塞等待,但如果在
abs_timeout
指定的绝对时间(基于CLOCK_REALTIME
)到达之前信号量仍未增加,则函数返回错误。
参数:
sem_t *sem
: 指向要操作的信号量对象的指针。const struct timespec *abs_timeout
: 指向一个timespec
结构体,指定了阻塞等待的绝对超时时间点。struct timespec { time_t tv_sec; long tv_nsec; };
。
返回值:
- 成功 (信号量减 1): 返回 0。
- 失败: 返回 -1,并设置
errno
。ETIMEDOUT
: 在超时时间到达前未能成功将信号量减 1。EINVAL
:sem
无效或abs_timeout
无效。EINTR
: 操作被信号中断。
3.6 sem_post()
- 释放(V 操作/加 1)
#include <semaphore.h>int sem_post(sem_t *sem);
功能: 对信号量 sem
执行 V 操作(原子地将其值加 1)。如果有任何线程/进程因此信号量而被阻塞,则其中一个会被唤醒。
参数:
sem_t *sem
: 指向要操作的信号量对象的指针。
返回值:
- 成功: 返回 0。
- 失败: 返回 -1,并设置
errno
。EINVAL
:sem
不是一个有效的信号量。EOVERFLOW
: 信号量的值增加将超过SEM_VALUE_MAX
。
3.7 sem_getvalue()
- 获取信号量当前值
#include <semaphore.h>int sem_getvalue(sem_t *sem, int *sval);
功能: 获取信号量 sem
的当前值,并将其存储在 sval
指向的整数中。注意:获取到的值可能在函数返回后立即就过时了(因为其他线程可能同时修改了信号量),主要用于调试或特定场景。
参数:
sem_t *sem
: 指向要查询的信号量对象的指针。int *sval
: 指向用于存储信号量当前值的整数的指针。
返回值:
- 成功: 返回 0。
- 失败: 返回 -1,并设置
errno
(如EINVAL
)。
4. 工作流程图 (sem_wait 和 sem_post)
graph TDsubgraph Thread A (Calls sem_wait)A1(Start sem_wait(sem)) --> A2{Check sem value > 0?};A2 -- Yes --> A3[Decrement sem value];A3 --> A4[Proceed];A2 -- No --> A5[Block Thread A];endsubgraph Thread B (Calls sem_post)B1(Start sem_post(sem)) --> B2[Increment sem value];B2 --> B3{Any threads blocked on sem?};B3 -- Yes --> B4[Wake up one blocked thread (e.g., Thread A)];B3 -- No --> B5[Return];B4 --> B5;endA5 --> B4; // Woken up by Thread B's postB4 -..-> A2; // Woken Thread A re-evaluates condition
流程图解释:
sem_wait 流程 (Thread A):
- 线程 A 调用
sem_wait
。 - 检查信号量的值是否大于 0。
- 是: 信号量减 1,线程 A 继续执行。
- 否: 线程 A 被阻塞,进入等待状态。
sem_post 流程 (Thread B):
- 线程 B 调用
sem_post
。 - 信号量的值加 1。
- 检查是否有其他线程(如线程 A)正因该信号量而被阻塞。
- 是: 唤醒其中一个被阻塞的线程。被唤醒的线程会回到
sem_wait
的检查点,此时信号量值已大于 0,它将成功减 1 并继续执行。 - 否: 直接返回。
- 是: 唤醒其中一个被阻塞的线程。被唤醒的线程会回到
5. C/C++ 测试用例:使用信号量保护临界区
这个例子演示了如何使用二值信号量(初始化为 1)来实现类似互斥锁的功能,保护一个共享计数器,防止多个线程同时修改导致竞态条件。
#include <iostream>
#include <vector>
#include <thread>
#include <semaphore.h> // For POSIX semaphores
#include <unistd.h> // For usleep// Global shared resource
int shared_counter = 0;// Global semaphore (acting as a mutex)
sem_t mutex_semaphore;// Number of threads and increments per thread
const int NUM_THREADS = 5;
const int INCREMENTS_PER_THREAD = 100000;// Thread function
void worker_thread(int id) {for (int i = 0; i < INCREMENTS_PER_THREAD; ++i) {// --- Enter Critical Section ---if (sem_wait(&mutex_semaphore) == -1) { // P operation (wait)perror("sem_wait failed");return; // Exit thread on error}// --- Critical Section Start ---// Access shared resourceint temp = shared_counter;// Simulate some work inside the critical section// usleep(1); // Optional small delay to increase chance of race condition without semaphoreshared_counter = temp + 1;// --- Critical Section End ---if (sem_post(&mutex_semaphore) == -1) { // V operation (post)perror("sem_post failed");// Handle error if necessary, though less critical than wait failure}// --- Exit Critical Section ---}std::cout << "Thread " << id << " finished." << std::endl;
}int main() {// Initialize the semaphore// pshared = 0: shared between threads of the same process// value = 1: initial value, acting as a binary semaphore (mutex)if (sem_init(&mutex_semaphore, 0, 1) == -1) {perror("sem_init failed");return 1;}std::cout << "Starting " << NUM_THREADS << " threads, each incrementing counter "<< INCREMENTS_PER_THREAD << " times." << std::endl;std::vector<std::thread> threads;for (int i = 0; i < NUM_THREADS; ++i) {threads.emplace_back(worker_thread, i);}// Wait for all threads to completefor (auto& t : threads) {t.join();}// Destroy the semaphoreif (sem_destroy(&mutex_semaphore) == -1) {perror("sem_destroy failed");// Continue cleanup if possible}std::cout << "All threads finished." << std::endl;std::cout << "Expected final counter value: " << NUM_THREADS * INCREMENTS_PER_THREAD << std::endl;std::cout << "Actual final counter value: " << shared_counter << std::endl;// Check if the result is correctif (shared_counter == NUM_THREADS * INCREMENTS_PER_THREAD) {std::cout << "Result is correct!" << std::endl;} else {std::cout << "Error: Race condition likely occurred!" << std::endl;}return 0;
}
编译与运行:
# Compile using g++ (or gcc if it were pure C)
# Link with pthread library for std::thread and potentially needed by semaphore implementation
g++ semaphore_example.cpp -o semaphore_example -pthread# Run the executable
./semaphore_example
预期输出:
程序会创建多个线程,每个线程对共享计数器执行大量递增操作。由于信号量的保护,最终的 shared_counter
值应该等于 NUM_THREADS * INCREMENTS_PER_THREAD
。如果没有信号量保护(注释掉 sem_wait
和 sem_post
),最终结果几乎肯定会小于预期值,因为会发生竞态条件。
6. 信号量的主要应用场景
- 互斥访问 (Mutual Exclusion): 使用初始值为 1 的二值信号量来保护临界区,确保同一时间只有一个线程/进程能访问共享资源或执行某段代码,功能类似互斥锁(Mutex)。
- 资源计数: 使用初始值为 N 的计数信号量来管理 N 个相同的资源(如数据库连接池中的连接、线程池中的工作线程等)。需要资源的线程执行 P 操作,释放资源的线程执行 V 操作。
- 同步 (Synchronization): 协调不同线程/进程的执行顺序。例如,一个线程(生产者)产生数据后执行 V 操作,另一个线程(消费者)在执行 P 操作时等待,直到有数据可用。
7. 注意事项与最佳实践
- 成对使用
sem_wait
和sem_post
: 在保护临界区的场景下,每个sem_wait
都必须有对应的sem_post
。忘记sem_post
会导致资源永久锁定(死锁的一种形式),而错误地多调用sem_post
会破坏互斥性。 - 初始化与销毁: 确保在使用前正确调用
sem_init
初始化信号量,并在不再需要时调用sem_destroy
销毁它。对于进程间共享的信号量,销毁逻辑需要特别注意。 - 错误检查: 务必检查
sem_init
,sem_wait
,sem_trywait
,sem_timedwait
,sem_post
,sem_destroy
等函数的返回值,并在失败时根据errno
进行适当的错误处理。 - 处理 EINTR:
sem_wait
和sem_timedwait
可能会被信号中断(返回 -1 且errno
为EINTR
)。健壮的程序应该捕获这种情况并通常重新尝试等待操作。 - 死锁 (Deadlock): 当多个线程/进程相互等待对方持有的信号量时,会发生死锁。设计锁的获取顺序是避免死锁的关键策略之一。例如,总是按相同的固定顺序获取多个信号量。
- 避免在信号处理函数中使用
sem_wait
: 信号处理函数的执行环境受限。在信号处理函数中调用可能阻塞的函数(如sem_wait
)通常是不安全的,可能导致
相关文章:
linux的信号量初识
Linux下的信号量(Semaphore)深度解析 在多线程或多进程并发编程的领域中,确保对共享资源的安全访问和协调不同执行单元的同步至关重要。信号量(Semaphore)作为经典的同步原语之一,在 Linux 系统中扮演着核心角色。本文将深入探讨…...
【安装指南】Centos7 在 Docker 上安装 RabbitMQ4.0.x
目录 前置知识:RabbitMQ 的介绍 一、单机安装 RabbitMQ 4.0.7版本 1.1 在线拉取镜像 二、延迟插件的安装 2.1 安装延迟插件 步骤一:下载延迟插件 步骤二:将延迟插件放到插件目录 步骤三:启动延迟插件 步骤四:重启 RabbitMQ 服务 步骤五:验收成果 步骤六:手动…...
Android和iOS测试的区别有哪些?
作为移动端测试工程师,Android 和 iOS 的测试差异直接影响测试策略设计。本文从测试环境、工具链、兼容性、发布流程等维度全面解析,并附实战建议。 1. 测试环境差异 维度AndroidiOS设备碎片化高(厂商/分辨率/系统版本多样)低(仅苹果设备,版本集中)系统开放性开放(可Ro…...
spring中的@PostConstruct注解详解
基本概念 PostConstruct 是 Java EE 规范的一部分,后来也被纳入到 Spring 框架中。它是一个标记注解,用于指示一个方法应该在依赖注入完成后被自动调用。 主要特点 生命周期回调:PostConstruct 标记的方法会在对象初始化完成、依赖注入完成…...
大模型开发学习笔记
文章目录 大模型基础大模型的使用大模型训练的阶段大模型的特点及分类大模型的工作流程分词化(tokenization)与词表映射 大模型的应用 进阶agent的组成和概念planning规划子任务分解ReAct框架 memory记忆Tools工具\工具集的使用langchain认知框架ReAct框架plan-and-Execute计划…...
【android Framework 探究】pixel 5 内核编译
相关文章: 【android Framework 探究】android 13 aosp编译全记录 【android Framework 探究】android 13 aosp 全记录 - 烧录 一,环境 主机 -> Ubuntu 18.04.6 LTS 内存 -> 16GB 手机 -> pixel 5 代号redfin。kernel代号redbull 二…...
PowerBI实现点击空白处隐藏弹窗(详细教程)
PowerBI点击空白处隐藏弹窗 第五届PowerBI可视化大赛中亚军作品:金融企业智慧经营分析看板 有个功能挺好玩的:点击空白处隐藏弹窗,gif动图如下: 我们以一个案例分享下实现步骤: 第一步, 先添加一个显示按钮ÿ…...
【git】获取特定分支和所有分支
1 特定分支 1.1 克隆指定分支(默认只下载该分支) git clone -b <分支名> --single-branch <仓库URL> 示例(克隆 某一个 分支): git clone -b xxxxxx --single-branch xxxxxxx -b :指定分支…...
Windows配置grpc
Windows配置grpc 方法一1. 使用git下载grph下载速度慢可以使用国内镜像1.1 更新子模块 2. 使用Cmake进行编译2.1 GUI编译2.2 命令行直接编译 3. 使用Visual Studio 生成解决方法 方法二1. 安装 vcpkg3.配置vckg的环境变量2. 使用 vcpkg 安装 gRPC3. 安装 Protobuf4. 配置 CMake…...
【学习笔记】深入理解Java虚拟机学习笔记——第2章 Java内存区域与内存溢出异常
第2章 Java内存区域与内存溢出异常 2.1 概述 略 2.2 运行时数据区域 2.2.1 程序计数器 线程私有,记录执行的字节码位置 2.2.2 Java 虚拟机栈 线程私有,存储一个一个的栈帧,通过栈帧的出入栈来控制方法执行。 -栈帧:对应一个…...
数字智慧方案6189丨智慧应急综合解决方案(46页PPT)(文末有下载方式)
资料解读:智慧应急综合解决方案 详细资料请看本解读文章的最后内容。 在当前社会环境下,应急管理的重要性愈发凸显。国务院发布的《“十四五” 国家应急体系规划》以及 “十四五” 智慧应急专项规划,明确了应急管理体系建设的方向和重点&…...
解决 3D Gaussian Splatting 中 SIBR 可视化组件报错 uv_mesh.vert 缺失问题【2025最新版!】
一、📌 引言 在使用 3D Gaussian Splatting(3DGS)进行三维重建和可视化的过程,SIBR_gaussianViewer_app 是一款官方推荐的本地可视化工具,允许我们在 GPU 上实时浏览重建结果。然而,许多用户在启动该工具时…...
见多识广4:Buffer与Cache,神经网络加速器的Buffer
目录 前言传统意义上的Buffer与Cache一言以蔽之定义与主要功能BufferCache 数据存储策略二者对比 神经网络加速器的bufferInput BufferWeight BufferOutput Buffer与传统buffer的核心区别总结 前言 知识主要由Qwen和Kimi提供,我主要做笔记。 参考文献: …...
微服务中组件扫描(ComponentScan)的工作原理
微服务中组件扫描(ComponentScan)的工作原理 你的问题涉及到Spring框架中ComponentScan的工作原理以及Maven依赖管理的影响。我来解释为什么能够扫描到common模块的bean而扫描不到其他模块的bean。 根本原因 关键在于**类路径(Classpath)**的包含情况: Maven依赖…...
C++之类和对象基础
⾯向对象三⼤特性:封装、继承、多态 类和对象 一.类的定义1. 类的定义格式2.类域 二.实例化1.对象2.对象的大小 三.this指针 在 C 的世界里,类和对象构成了面向对象编程(Object-Oriented Programming,OOP)的核心框架&…...
【DIY小记】新手小白超频遇到黑屏问题解决分享
最近玩FPS游戏的时候,发现以前一顿操作超频之后的电脑,有一定概率会出问题。具体表现比如一种是,电脑显示器直接黑屏,所有键盘交互没有响应,只能直接重启电脑,还有一种是偶现卡顿,直接死机或者卡…...
虚幻引擎 IK Retargeter 编辑器界面解析
我来为您详细解释这段关于虚幻引擎IK Retargeter编辑器界面的文本,它描述了动画重定向系统的核心组件和工作原理。 Retarget Phases (重定向阶段) 这部分介绍了动画重定向过程中的三个关键计算阶段,每个阶段都可以单独启用或禁用,这对于调试…...
uc系统中常用命令、标准C库函数和系统调用
目录 一、常用命令 env echo $name 键值 export name unset name gcc -c xxx.c ar 命令 ar -r libxxx.a xxx1.o xxx2.o gcc -c -fpic xxx.c gcc -shared -fpic xxx1.c xxx2.c -o libxxx.so kill [-信号] PID kill -l 软链接:ln -s xxx yyy 硬链接&…...
OpenHarmony - 驱动使用指南,HDF驱动开发流程
OpenHarmony - HDF驱动开发流程 概述 HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理、驱动消息机制和配置管理。并以组件化驱动模型作为核心设计思路,让驱动开发…...
C++负载均衡远程调用学习之UDP SERVER功能
目录 1.LARSV0.9-配置功能 2.LARSV0.10-upd-server的实现 3.LARSV0.10-udp-client的实现 1.LARSV0.9-配置功能 2.LARSV0.10-upd-server的实现 3.LARSV0.10-udp-client的实现...
word交叉引用图片、表格——只引用编号的处理方法
交叉引用图片/表格 在“引用”选项卡上的“题注”组中,单击“插入题注”。勾选【从题注中排除标签】。在文中插入题注。 【注 意】 这时候插入的题注只有编号项了。然后手动打上标签【TABLE】,并在标签和编号项之间加上【样式分隔符,AltCt…...
平台介绍-开放API接口-鉴权
平台的理念是一个组织内部只建一套系统。但是现实情况是,组织内部已经建立了很多系统,是不能一次性替代的,只能先搭起平台,然后逐步开始替换。这样就不可避免的存在其他系统和平台进行交互的问题。 平台为此设计了开放API接口。其…...
【Bootstrap V4系列】 学习入门教程之 组件-警告框(Alert)
Bootstrap V4 学习入门教程之 组件-警告框(Alert) 警告框(Alert)一、示例二、链接的颜色三、添加其它内容四、关闭警告框 通过 JavaScript 触发行为触发器本组件所暴露的事件 警告框(Alert) 通过精炼且灵活…...
【服务器通信-socket】——int socket(int domain, int type, int protocol);
#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); domain: AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址 AF_INET6 与上面类似,不过是来用IPv6的地…...
洛谷P1014(Cantor 表[NOIP 1999 普及组])题解
题目大意:求Cantor表(按照Z字形排列(如第一项是1/1,然后是1/2,2/1,3/1,2/2))的第N项。 那么,我们需要找出Cantor表的排列规律。根据题目中的Z字形描述&#x…...
【愚公系列】《Manus极简入门》012-自我认知顾问:“内在探索向导”
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! …...
密码学_加密
目录 密码学 01 密码基础进制与计量 02 加解密基操 替换 移位 编码 编码 置换 移位 加解密强度 03 对称加密算法(私钥) 工作过程 缺陷 对称加密算法列举? DES DES算法架构 DES分组加密公式 DES中ECB-CBC两种加密方式 3DES 由于DES密钥太短…...
w317汽车维修预约服务系统设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
云盘系统设计
需求背景 网盘面向大量C端用户 1000w用户 DAU 20% 每天10次 QPS: 1000w * 0.2 * 10 / 100k 500 峰值估计:500 * 5 2500 功能需求 支持上传,下载,多端共同在线编辑,数据冲突处理 非功能需求 1.latency 20s左右 2.可用性与…...
西电雨课堂《知识产权法》课后作业答案
目录 第 1 章 1.1 课后作业 1.2 课后作业 第 2 章 2.1 课后作业 2.2 课后作业 2.3 课后作业 2.4 课后作业 2.5 课后作业 2.6 课后作业 2.7 课后作业 2.8 课后作业 2.9 课后作业 2.10 课后作业 第 3 章 3.1 课后作业 3.2 课后作业 3.3 课后作业 3…...
通信协议记录仪-产品规格书
以下是为 通信协议记录仪(ProtoLogger Pro) 的详细产品规格书,覆盖 技术细节、场景需求、竞品差异化,确保可作为产品开发、市场营销及竞品分析的核心依据。 通信协议记录仪产品规格书 产品名称:ProtoLogger Pro(中文名称:蹲守…...
订单系统冷热分离方案:优化性能与降低存储成本
随着时间推移,订单数据不断积累。在电商平台或者服务型应用中,订单数据是核心数据之一。然而,随着数据量的增长,如何高效存储、管理和查询这些数据成为了系统架构设计的重要问题。在大多数情况下,订单数据的处理不仅涉…...
数据结构学习笔记
第 1 章 绪论 【考纲内容】 (一)数据结构的基本概念 (二)算法的基本概念 算法的时间复杂度和空间复杂度 【知识框架】 【复习提示】 本章内容是数据结构概述,并不在考研大纲中。读者可通过对本章的学习,初步…...
读懂 Vue3 路由:从入门到实战
在构建现代化单页应用(SPA)时,Vue3 凭借其简洁高效的特性成为众多开发者的首选。 而 Vue3 路由(Vue Router)则是 Vue3 生态中不可或缺的一部分,它就像是单页应用的 “导航地图”,帮助用户在不同…...
Aws S3上传优化
上传大约 3.4GB 的 JSON 文件,zip算法压缩后约为 395MB,上传至 S3 效率优化,有一些优化方案可以提高上传速率。下面是几种可能的优化方式,包括选择压缩算法、调整上传方式、以及其他可能的方案。 方案 1. 选择更好的压缩算法 压…...
Python 数据智能实战 (8):基于LLM的个性化营销文案
写在前面 —— 告别群发轰炸,拥抱精准沟通:用 LLM 为你的用户量身定制营销信息 在前面的篇章中,我们学习了如何利用 LLM 增强用户理解(智能分群)、挖掘商品关联(语义购物篮)、提升预测精度(融合文本特征的流失预警)。我们不断地从数据中提取更深层次的洞察。 然而,…...
html:table表格
表格代码示例: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><!-- 标准表格。 --><table border"5"cellspacing&qu…...
2.maven 手动安装 jar包
1.背景 有的时候,maven仓库无法下载,可以手动安装。本文以pentaho-aggdesigner-algorithm-5.1.5-jhyde.jar为例。 2.预先准备 下载文件到本地指定位置。 2.1.安装pom mvn install:install-file \-Dfile/home/wind/tmp/pentaho-aggdesigner-5.1.5-jh…...
C++ unordered_set unordered_map
上篇文章我们讲解了哈希表的实现,这节尝试使用哈希表来封装unordered_set/map 1. unordered_set/map的框架 封装的过程实际上与set/map类似,在unordered_set/map层传递一个仿函数,用于取出key值 由于我们平常使用的都是unordered_set/map&…...
第37课 绘制原理图——放置离页连接符
什么是离页连接符? 前边我们介绍了网络标签(Net Lable),可以让两根导线“隔空相连”,使原理图更加清爽简洁。 但是网络标签的使用也具有一定的局限性,对于两张不同Sheet上的导线,网络标签就不…...
< 自用文 Texas style Smoker > 美式德克萨斯烟熏炉 从设计到实现 (第一部分:烹饪室与燃烧室)
原因: 没钱还馋! 但有手艺。 预计目标: 常见的两种偏置式烟熏炉(Offset Smoker) 左边边是标准偏置式(Standard Offset),右边是反向流动式(Reverse Flow Offset&#x…...
【现代深度学习技术】现代循环神经网络03:深度循环神经网络
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重…...
AimRT从入门到精通 - 03Channel发布者和订阅者
刚接触AimRT的小伙伴可能会疑惑,这个Channel和RPC(后面讲的)到底是什么呢? 但是当我们接触了之后,就会发现,其本质类似ROS的Topic通信!(其本质基于发布订阅模型) 接下来…...
MySQL初阶:数据库基础,数据库和表操作,数据库中的数据类型
1.数据库基础 数据库是一个客户端——服务器结构的程序。 服务器是真正的主体,负责保存和管理数据,数据都存储在硬盘上 数据库处理的主要内容是数据的存储,查找,修改,排序,统计等。 关系型数据库&#…...
AI 驱动的智能交通系统:从拥堵到流畅的未来出行
最近研学过程中发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击链接跳转到网站人工智能及编程语言学习教程。读者们可以通过里面的文章详细了解一下人工智能及其编程等教程和学习方法。下面开始对正文内容的…...
Python清空Word段落样式的方法
在 Python 中,你可以使用 python-docx 库来操作 Word 文档,包括清空段落样式。以下是几种清空段落样式的方法: 方法一:直接设置段落样式为"Normal" from docx import Documentdoc Document(your_document.docx) # 打…...
[javaEE]网络编程
目录 socket对tcp ServerSocket ServerSocket 构造方法: ServerSocket 方法: socket 实现回显服务器和客户端 由于我们之前已经写多了socket对udq的实现,所以我们这节,主要将重心放在Tcp之上 socket对tcp ServerS…...
组件通信-mitt
mitt:与消息订阅与发布(pubsub)功能类似,可以实现任意组件间通信。 第一步:安装mitt npm i mitt 第二步:新建文件:src\utils\emitter.ts // 引入mitt import mitt from "mitt"; //调…...
微软发布了最新的开源推理模型套件“Phi-4-Reasoning
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
Socat 用法详解:网络安全中的瑞士军刀
Socat 用法详解:网络安全中的强大工具 引言 socat(SOcket CAT)是一款功能强大的命令行工具,被誉为“网络瑞士军刀”,广泛应用于数据传输、端口转发和网络调试等场景。它支持多种协议和数据通道(如文件、管…...