当前位置: 首页 > news >正文

【Linux系统编程】:自旋锁,读写锁

文章目录

  • 前言
  • 1. POSIX自旋锁
      • 1.1.定义自旋锁
      • 1.2.初始化
      • 1.3. 加锁
      • 1.4. 尝试加锁操作
      • 1.5. 解锁操作
      • 1.6. 销毁操作
      • 1.7.示例
      • 1.8.优缺点
        • 优点
        • 缺点
      • 1.9.适用场景
  • 2. 读写锁
    • 2.1 读写锁的工作原理
    • 2.2 读写模型
    • 2.3 常用接口
      • 2.3.1 定义锁并初始化
      • 2.3.2 申请读锁
      • 2.3.3 申请写锁
      • 2.3.4 解锁
      • 2.3.5 销毁锁
      • 2.3.6 设置优先级
      • 2.3.7 示例

前言

前面我们所谈论的锁,都是挂起等待锁,也就是当线程获取已经被持有的“挂起等待锁”时,会被操作系统挂起(陷入阻塞状态并加入等待队列中),但自旋锁不会。
自旋锁是一种忙等待锁,当一个线程尝试获取自旋锁时,如果锁当前已经被其他线程持有,该线程不会进入睡眠状态,而是会持续检查锁的状态,直到获取到锁为止。这种持续的检查过程就像在 “自旋” 一样,因此被称为自旋锁。pthread_mutex_trylock
如果我们想在应用层做一个自旋锁,可以用互斥量的接口pthread_mutex_trylock,在这里插入图片描述
工作原理:
在这里插入图片描述
我们只要将pthread_mutex_trylock放在一个循环里,就可以实现“自旋锁”。我们也可以不用互斥量,因为POSIX线程库提供了自旋锁相关接口。

1. POSIX自旋锁

1.1.定义自旋锁

pthread_spinlock_t 是 POSIX 线程库中用于实现自旋锁的数据类型。在使用自旋锁前,我们先要定义一把。

#include <pthread.h>
pthread_spinlock_t slock;

1.2.初始化

在使用自旋锁之前,需要对其进行初始化:

#include <pthread.h>int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
  • 参数
    • lock:指向 pthread_spinlock_t 类型的指针,表示要初始化的自旋锁。
    • pshared:指定自旋锁的共享属性,有两个可选值:
      • PTHREAD_PROCESS_SHARED:表示该自旋锁可以在多个进程间共享。
      • PTHREAD_PROCESS_PRIVATE:表示该自旋锁只能在同一进程内的多个线程间使用,这是比较常见的用法。
  • 返回值:如果初始化成功,返回 0;如果出现错误,返回相应的错误码。

1.3. 加锁

int pthread_spin_lock(pthread_spinlock_t *lock);

该函数用于尝试获取指定的自旋锁。如果锁当前未被其他线程持有,调用线程会立即获取锁并继续执行;如果锁已经被其他线程持有,调用线程会进入自旋状态,不断检查锁的状态,直到成功获取锁。返回值为 0 表示成功获取锁,出现错误时返回相应的错误码。

1.4. 尝试加锁操作

int pthread_spin_trylock(pthread_spinlock_t *lock);

这是一个非阻塞的加锁操作。如果锁当前未被其他线程持有,调用线程会立即获取锁并返回 0;如果锁已经被其他线程持有,函数会立即返回 EBUSY,而不会让线程进入自旋状态。同样,出现其他错误时返回相应的错误码。

1.5. 解锁操作

int pthread_spin_unlock(pthread_spinlock_t *lock);

该函数用于释放指定的自旋锁。调用线程必须是当前持有该自旋锁的线程,释放锁后,其他等待该锁的线程有机会获取它。返回值为 0 表示解锁成功,出现错误时返回相应的错误码。

1.6. 销毁操作

int pthread_spin_destroy(pthread_spinlock_t *lock);

当自旋锁不再使用时,需要调用该函数进行销毁,释放相关资源。返回值为 0 表示销毁成功,出现错误时返回相应的错误码。

1.7.示例

#include <stdio.h>
#include <pthread.h>pthread_spinlock_t spinlock;
int shared_variable = 0;void* thread_function(void* arg) {pthread_spin_lock(&spinlock);// 临界区,对共享资源进行操作shared_variable++;printf("Thread %ld: shared_variable = %d\n", (long)arg, shared_variable);pthread_spin_unlock(&spinlock);return NULL;
}int main() {pthread_t threads[2];// 初始化自旋锁pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);for (long i = 0; i < 2; i++) {pthread_create(&threads[i], NULL, thread_function, (void*)i);}for (int i = 0; i < 2; i++) {pthread_join(threads[i], NULL);}// 销毁自旋锁pthread_spin_destroy(&spinlock);return 0;
}

在上述代码中,首先使用 pthread_spin_init 初始化自旋锁,然后创建两个线程,每个线程在进入临界区前调用 pthread_spin_lock 获取锁,对共享变量 shared_variable 进行操作,操作完成后调用 pthread_spin_unlock 释放锁。最后,使用 pthread_spin_destroy 销毁自旋锁。

1.8.优缺点

优点
  • 低延迟:在锁被持有的时间较短的情况下,自旋锁的性能优势明显。由于线程不需要进行上下文切换,避免了睡眠和唤醒的开销,能够快速获取锁并继续执行,从而提供较低的延迟。
  • 实现简单:自旋锁的实现相对简单,不需要复杂的操作系统调度机制支持,只需要使用原子操作来实现锁的状态检查和设置。
缺点
  • CPU 资源浪费:如果锁被持有的时间较长,自旋的线程会持续占用 CPU 资源进行空转,导致 CPU 资源的浪费,降低系统的整体性能。
  • 可能导致优先级反转:在某些情况下,可能会出现优先级反转问题。例如,低优先级的线程持有自旋锁,高优先级的线程需要该锁,高优先级线程会自旋等待,导致低优先级线程无法及时执行完并释放锁,从而影响系统的实时性。

1.9.适用场景

  • 锁持有时间短:自旋锁适用于锁被持有的时间非常短的场景,例如对某个共享变量进行简单的读写操作。在这种情况下,线程自旋等待的时间不会太长,不会造成过多的 CPU 资源浪费。
  • 多核系统:在多核系统中,多个线程可以并行执行,自旋的线程可以在其他 CPU 核心上继续自旋,而不会阻塞整个系统。因此,自旋锁在多核系统中更为适用。
    来源:https://www.doubao.com/chat/

2. 读写锁

在编写多线程的时候,可能会出现线程间对于临界资源的访问需求要远远大于修改需求,访问的频率远远高于修改的频率,而访问往往伴随着查找的操作,给这种临界区加锁,可能会极大地降低程序运行效率。那么有没有一种锁,专门处理这种多访问少修改的情况呢? 有,那就是读写锁。

2.1 读写锁的工作原理

当多个线程同时对共享资源进行读操作时,一般不会出现数据竞争问题,而线程进行写操作时,必须保证只有当前唯一一个线程进行写操作,且其他线程无法进行读操作,以确保数据的一致性。
因此,读写锁允许多个线程同时获取读锁进行读操作,但在有线程持有写锁时,其他线程不能获取读锁或写锁;同样,当有线程持有读锁时,其他线程不能获取写锁。

2.2 读写模型

多线程间的多访问少修改,访问对于读,修改对应写,针对这种场景,我们假想出一种读写模型(类似于CP模型,具体的应用就是读写锁。),该模型中存在三个关系两个角色一个场所。
在这里插入图片描述
问题来了,为什么读写模型中,读与读之间是“共享”的,可以并发进行,而CP模型中,消费与消费之间却是互斥的?
因为读数据没有修改临界资源,而消费数据修改了临界资源。所以我们只要关注写之间的互斥以及读写之间的互斥和同步。
在读写模型中,由于读的线程较多以及读的频率较高,在竞争锁时,写的线程容易竞争不过从而产生饥饿。

2.3 常用接口

2.3.1 定义锁并初始化

  • 静态初始化(在编译时就确定读写锁初始状态)
#include <pthread.h>
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
  • 动态初始化
#include <pthread.h>pthread_rwlock_t rwlock;
int ret = pthread_rwlock_init(&rwlock, NULL);
if (ret != 0) {// 处理初始化失败的情况
}

pthread_rwlock_init函数的第一个参数是指向读写锁的指针;
第二个参数是指向读写锁属性对象的指针,传入NULL表示使用默认属性。

2.3.2 申请读锁

 请求读锁(共享)
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
//如果当前没有线程持有写锁,调用线程可以立即获取读锁并继续执行;
//若有线程持有写锁,调用线程会被阻塞,直到写锁被释放。//尝试非阻塞加锁(读)
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
//若当前没有线程持有写锁,调用线程能立即获取读锁并返回0;
//若有线程持有写锁,函数会立即返回EBUSY,线程不会阻塞。

2.3.3 申请写锁

//请求写锁(独占)
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
/尝试非阻塞加锁(写)
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

2.3.4 解锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

2.3.5 销毁锁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

2.3.6 设置优先级

在 POSIX 线程库中,读写锁的属性可以通过属性对象来进行设置和管理。pthread_rwlockattr_setkind_np 函数用于设置读写锁的竞争策略,也就是当有读线程和写线程同时竞争读写锁时,决定哪个线程优先获取锁。这里的 “np” 通常表示 “non - portable”(非移植性),意味着这个函数不是 POSIX 标准的一部分,不同的操作系统实现可能会有所不同。详情参考https://www.doubao.com/chat/。

2.3.7 示例

#include <vector>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include <atomic>  // 使用 std::atomic 来保证线程安全// 使用 std::atomic 来保证对 ticket 的操作是线程安全的
std::atomic<int> ticket(1000);
pthread_rwlock_t rwlock;// 读者线程函数
void *reader(void *arg) {// 将传入的 void* 指针转换为 std::string*std::string *id = static_cast<std::string*>(arg);while (true) {// 获取读锁pthread_rwlock_rdlock(&rwlock);// 检查 ticket 是否小于等于 0if (ticket.load() <= 0) {// 释放读锁pthread_rwlock_unlock(&rwlock);break;}// 打印当前 ticket 值printf("%s: %d\n", id->c_str(), ticket.load());// 释放读锁pthread_rwlock_unlock(&rwlock);// 休眠 1 微秒usleep(1);}// 释放分配的内存delete id;return nullptr;
}// 写者线程函数
void *writer(void *arg) {// 将传入的 void* 指针转换为 std::string*std::string *id = static_cast<std::string*>(arg);while (true) {// 获取写锁pthread_rwlock_wrlock(&rwlock);// 检查 ticket 是否小于等于 0if (ticket.load() <= 0) {// 释放写锁pthread_rwlock_unlock(&rwlock);break;}// 打印当前 ticket 值并递减 ticketprintf("%s: %d\n", id->c_str(), ticket.fetch_sub(1));// 释放写锁pthread_rwlock_unlock(&rwlock);// 休眠 1 微秒usleep(1);}// 释放分配的内存delete id;return nullptr;
}// 线程属性结构体
struct ThreadAttr {pthread_t tid;  // 线程 IDstd::string id; // 线程标识符
};// 创建读者线程标识符
std::string create_reader_id(std::size_t i) {// 使用 ostringstream 进行 string 拼接std::ostringstream oss;oss << "thread reader " << i;return oss.str();
}// 创建写者线程标识符
std::string create_writer_id(std::size_t i) {// 使用 ostringstream 进行 string 拼接std::ostringstream oss;oss << "thread writer " << i;return oss.str();
}// 初始化读者线程
void init_readers(std::vector<ThreadAttr>& vec) {for (std::size_t i = 0; i < vec.size(); ++i) {vec[i].id = create_reader_id(i);// 动态分配内存并传递给线程函数std::string *id = new std::string(vec[i].id);pthread_create(&vec[i].tid, nullptr, reader, id);}
}// 初始化写者线程
void init_writers(std::vector<ThreadAttr>& vec) {for (std::size_t i = 0; i < vec.size(); ++i) {vec[i].id = create_writer_id(i);// 动态分配内存并传递给线程函数std::string *id = new std::string(vec[i].id);pthread_create(&vec[i].tid, nullptr, writer, id);}
}// 回收线程
void join_threads(const std::vector<ThreadAttr>& vec) {// 按创建的顺序回收线程for (const auto& ta : vec) {void *id = nullptr;pthread_join(ta.tid, &id);// 释放传递给线程的内存delete static_cast<std::string*>(id);}
}// 初始化读写锁
void init_rwlock() {
#if 0   // 写优先pthread_rwlockattr_t attr;pthread_rwlockattr_init(&attr);pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);pthread_rwlock_init(&rwlock, &attr);pthread_rwlockattr_destroy(&attr);
#else   // 读优先,会造成写饥饿pthread_rwlock_init(&rwlock, nullptr);
#endif
}int main() {// 测试效果不明显的情况下,可以加大 reader_nr// 但也不能太大,超过一定阈值后系统就调度不了主线程了const std::size_t reader_nr = 1000;const std::size_t writer_nr = 2;std::vector<ThreadAttr> readers(reader_nr);std::vector<ThreadAttr> writers(writer_nr);init_rwlock();init_readers(readers);init_writers(writers);join_threads(writers);join_threads(readers);pthread_rwlock_destroy(&rwlock);return 0;
}

相关文章:

【Linux系统编程】:自旋锁,读写锁

文章目录 前言1. POSIX自旋锁1.1.定义自旋锁1.2.初始化1.3. 加锁1.4. 尝试加锁操作1.5. 解锁操作1.6. 销毁操作1.7.示例1.8.优缺点优点缺点 1.9.适用场景 2. 读写锁2.1 读写锁的工作原理2.2 读写模型2.3 常用接口2.3.1 定义锁并初始化2.3.2 申请读锁2.3.3 申请写锁2.3.4 解锁2.…...

位运算及常用技巧

涉及位运算的运算符如下表所示&#xff1a; 位运算的运算律&#xff1a; 负数的位运算 首先&#xff0c;我们要知道&#xff0c;在计算机中&#xff0c;运算是使用的二进制补码&#xff0c;而正数的补码是它本身&#xff0c;负数的补码则是符号位不变&#xff0c;其余按位取反…...

Chrome 浏览器:互联网时代的浏览利器

Chrome 浏览器&#xff1a;互联网时代的浏览利器 引言 在互联网时代&#xff0c;浏览器已经成为我们日常生活中不可或缺的工具。作为全球最受欢迎的浏览器之一&#xff0c;Chrome 浏览器凭借其出色的性能、丰富的扩展程序和简洁的界面&#xff0c;赢得了广大用户的喜爱。本文…...

web-文件上传-CTFHub

前言 在众多的CTF平台当中&#xff0c;作者认为CTFHub对于初学者来说&#xff0c;是入门平台的不二之选。CTFHub通过自己独特的技能树模块&#xff0c;可以帮助初学者来快速入门。具体请看官方介绍&#xff1a;CTFHub。 作者更新了CTFHub系列&#xff0c;希望小伙伴们多多支持…...

【react】react面试题

react面试题 对 React 的理解、特性 react18有哪些更新 JSX是什么 解释为什么浏览器不能读取jsx ReactNative中&#xff0c;如何解决8081端口被占用而提示无法访问的问题&#xff1f; React 生命周期 react事件机制 react 组件传值 React改变state的方式 re…...

逐笔成交逐笔委托Level2高频数据下载和分析:20250206

Level2逐笔成交逐笔委托数据分享下载 通过Level2逐笔成交和逐笔委托这种每一笔的毫秒级别的数据可以分析出很多有用的点&#xff0c;包括主力意图&#xff0c;虚假动作&#xff0c;让任何操作无所遁形。适合交易大师来分析主力规律&#xff0c;也适合人工智能领域的机器学习&a…...

__cvta_generic_to_shared

一 测试代码 #include <cuda_runtime.h> #include <cstdio> #include <cstdint>__global__ void test_cp_async(int* __restrict__ A,int* __restrict__ B){int tid = threadIdx.x;A[tid] = tid;__shared__ int smem[32];size_t smemAddr = __cvta_generic_…...

C++学习——缺省参数、重载函数、引用

目录 前言 一、缺省参数 1.1概念 1.2写法 1.3半缺省 1.4使用 二、重载函数 2.1.概念 2.2类型 2.3参数 2.4顺序 2.5问题 2.6原理 三、引用 1、引用是什么&#xff1f; 2、引用的使用方法 3、引用特性 1、引用在定义的时候必须要初始化 2、一个变量会有多个引用…...

docker-compose 配置nginx

前言 前端打包的dist文件在宿主机&#xff0c;nginx运行在docker-compose 问题 nginx.conf 在本地配置可以生效&#xff0c;但是链接到容器就报错 基于本地的nginx运行&#xff0c;本地nginx.conf 如下 server {listen 8081;location / {root /usr/local/software/testweb/…...

LQB(0)-python-基础知识

一、Python开发环境与基础知识 python解释器&#xff1a;用于解释python代码 方式&#xff1a; 1.直接安装python解释器 2.安装Anaconda管理python环境 python开发环境&#xff1a;用于编写python代码 1.vscode 2.pycharm # 3.安装Anaconda后可以使用网页版的jupyter n…...

【C语言】指针运算与数组关系:详细分析与实例讲解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;1. 指针的基础运算1.1 指针的加减运算1.2 指针加整数与指针减整数1.3 指针与指针的运算 &#x1f4af;2. 指针的实际应用&#xff1a;模拟 strlen 函数2.1 使用指针模拟…...

C++数组

指针&#xff0c;是C数组工作方式的基础。 数组&#xff0c;基本上是元素的集合。按特定的顺序排列的一堆东西。 C数组&#xff0c;就是表示一堆的变量组成的集合。一般是一行相同类型的变量。 例子&#xff1a; #include <iostream> int main() {int example[5];exa…...

OSPF基础(2)

一、LSA的头部 LSA是OSPF的一个核心内容&#xff0c;如果没有LSA&#xff0c;OSPF是无法描述网络的拓扑结构及网段信息的,也无法传递路由信息&#xff0c;更加无法正常工作&#xff0c;在OSPFV2中&#xff0c;需要我们掌握的主要有6种。 LSA头部一共20byte&#xff0c;每个字段…...

DeepSeek R1 简单指南:架构、训练、本地部署和硬件要求

DeepSeek 的 LLM 推理新方法 DeepSeek 推出了一种创新方法&#xff0c;通过强化学习 (RL) 来提高大型语言模型 (LLM) 的推理能力&#xff0c;其最新论文 DeepSeek-R1 对此进行了详细介绍。这项研究代表了我们如何通过纯强化学习来增强 LLM 解决复杂问题的能力&#xff0c;而无…...

javaEE-6.网络原理-http

目录 什么是http? http的工作原理&#xff1a; 抓包工具 fiddler的使用 HTTP请求数据: 1.首行:​编辑 2.请求头(header) 3.空行&#xff1a; 4.正文&#xff08;body&#xff09; HTTP响应数据 1.首行&#xff1a;​编辑 2.响应头 3.空行&#xff1a; 4.响应正文…...

把bootstrap5.3.3整合到wordpress主题中的方法

以下是将 Bootstrap 5.3.3 整合到 WordPress 主题中的方法&#xff1a; 下载 Bootstrap 文件&#xff1a;从 Bootstrap 官网下载最新的 5.3.3 版本的 CSS 和 JavaScript 文件。 上传文件到主题目录&#xff1a;将下载的 CSS 文件上传到 WordPress 主题文件夹中的 /css 文件夹…...

深度整理总结MySQL——Buffer Pool工作原理

Buffer Pool工作原理 前言为什么会有Buffer PoolBuffer Pool介绍Buffer Pool有多大Buffer Pool缓存什么呢Buffer Pool碎片空间查询一条记录&#xff0c;就只需要缓冲一条记录吗 如何管理Buffer Pool如何管理空闲页如何管理脏页如何提高缓存命中率 LRU带来的问题预读失效Buffer …...

langchain教程-9.Retriever/检索器

前言 该系列教程的代码: https://github.com/shar-pen/Langchain-MiniTutorial 我主要参考 langchain 官方教程, 有选择性的记录了一下学习内容 这是教程清单 1.初试langchain2.prompt3.OutputParser/输出解析4.model/vllm模型部署和langchain调用5.DocumentLoader/多种文档…...

凝思60重置密码

凝思系统重置密码 - 赛博狗尾草 - 博客园 问题描述 凝思系统进入单用户模式&#xff0c;在此模式下&#xff0c;用户可以访问修复错误配置的文件。也可以在此模式下安装显卡驱动&#xff0c;解决和已加载驱动的冲突问题。 适用范围 linx-6.0.60 linx-6.0.80 linx-6.0.100…...

指针基础知识1

1.内存和地址 1.案例 我们可以借助一个生活在的案例来熟悉电脑中内存和地址的关系&#xff1a; 假设有⼀栋宿舍楼&#xff0c;把你放在楼里&#xff0c;楼上有100个房间&#xff0c;但是房间没有编号&#xff0c;你的⼀个朋友来找你玩&#xff0c; 如果想找到你&#xff0c;…...

大数据学习之Spark分布式计算框架RDD、内核进阶

一.RDD 28.RDD_为什么需要RDD 29.RDD_定义 30.RDD_五大特性总述 31.RDD_五大特性1 32.RDD_五大特性2 33.RDD_五大特性3 34.RDD_五大特性4 35.RDD_五大特性5 36.RDD_五大特性总结 37.RDD_创建概述 38.RDD_并行化创建 演示代码&#xff1a; // 获取当前 RDD 的分区数 Since ( …...

Windows本地部署DeepSeek-R1大模型并使用web界面远程交互

文章目录 前言1. 安装Ollama2. 安装DeepSeek-r1模型3. 安装图形化界面3.1 Windows系统安装Docker3.2 Docker部署Open WebUI3.3 添加Deepseek模型 4. 安装内网穿透工具5. 配置固定公网地址 前言 最近爆火的国产AI大模型Deepseek详细大家都不陌生&#xff0c;不过除了在手机上安…...

【Linux系统】线程:线程控制

一、POSIX线程库 与线程有关的函数构成了一个完整的系列&#xff0c;绝大多数函数的名字都是以“pthread_”打头的。使用这些函数库&#xff0c;要通过引入头文件 <pthread.h>。链接这些线程函数库时要使用编译器命令的 -lpthread 选项。 二、轻量级进程创建&#xff1a…...

GoFrame 微服务开发指南

基本介绍 GoFrame 框架支持微服务模式开发&#xff0c;提供了常用的微服务组件、开发工具、开发教程帮助团队快速微服务转型。 微服务组件简介 GoFrame 微服务组件具有低耦合及通用化设计&#xff0c;组件化使用支持大部分的微服务通信协议。在官方文档中&#xff0c;主要以…...

Python-基于PyQt5,Pillow,pathilb,imageio,moviepy,sys的GIF(动图)制作工具(进阶版)

前言&#xff1a;在抖音&#xff0c;快手等社交平台上&#xff0c;我们常常见到各种各样的GIF动画。在各大评论区里面&#xff0c;GIF图片以其短小精悍、生动有趣的特点&#xff0c;被广泛用于分享各种有趣的场景、搞笑的瞬间、精彩的动作等&#xff0c;能够快速吸引我们的注意…...

PhpStorm下载、安装、配置教程

前面的文章中&#xff0c;都是把.php文件放在WampServer的www目录下&#xff0c;通过浏览器访问运行。这篇文章就简单介绍一下PhpStorm这个php集成开发工具的使用。 目录 下载PhpStorm 安装PhpStorm 配置PhpStorm 修改个性化设置 修改字符编码 配置php的安装路径 使用Ph…...

春节假期旅游热潮下,景区医疗安全如何全面升级?

春节假期旅游热潮下&#xff0c;景区医疗安全如何全面升级&#xff1f; 随着旅游业的不断繁荣&#xff0c;春节假期期间&#xff0c;各大景区再次迎来了游客的高峰期。面对如此庞大的客流量&#xff0c;景区不仅要在服务接待上下功夫&#xff0c;更要将医疗安全保障工作提升到…...

惠普HP工作站如何关闭关闭RAID?

惠普HP工作站如何关闭关闭RAID&#xff1f; 前言进入BIOS进入“先进”选项卡&#xff0c;点击“系统选项”。取消勾选“sSATA控制器RAID模式”&#xff0c;按下F10保存重启。 前言 惠普工作站默认启用了RAID模式&#xff0c;导致许多PE工具无法识别RAID模式下的硬盘。可以通过…...

ESP-Skainet智能语音助手,ESP32-S3物联网方案,设备高效语音交互

在科技飞速发展的今天&#xff0c;智能语音助手正逐渐渗透到我们生活的方方面面&#xff0c;而智能语音助手凭借其卓越的技术优势&#xff0c;成为了智能生活领域的一颗璀璨明星。 ESP-Skainet智能语音助手的强大之处在于其支持唤醒词引擎&#xff08;WakeNet&#xff09;、离…...

mac下生成.icns图标

笔记原因&#xff1a; 今日需要在mac下开发涉及图标文件的使用及icons文件的生成&#xff0c;所以记录一下。 网络上都是一堆命令行需要打印太麻烦了&#xff0c;写一个一键脚本。 步骤一 将需要生成的png格式文件重命名为“pic.png” mv xxxx.png pic.png 步骤二 下载我…...

【MySQL】centos 7 忘记数据库密码

vim /etc/my.cnf文件&#xff1b; 在[mysqld]后添加skip-grant-tables&#xff08;登录时跳过权限检查&#xff09; 重启MySQL服务&#xff1a;sudo systemctl restart mysqld 登录mysql&#xff0c;输入mysql –uroot –p&#xff1b;直接回车&#xff08;Enter&#xff09; 输…...

【kafka的零拷贝原理】

kafka的零拷贝原理 一、零拷贝技术概述二、Kafka中的零拷贝原理三、零拷贝技术的优势四、零拷贝技术的实现细节五、注意事项一、零拷贝技术概述 零拷贝(Zero-Copy)是一种减少数据拷贝次数,提高数据传输效率的技术。 在传统的数据传输过程中,数据需要在用户态和内核态之间…...

【JavaEE】Spring Web MVC

目录 一、Spring Web MVC简介 1.1 MVC简介1.2 Spring MVC1.3 RequestMapping注解1.3.1 使用1.3.2 RequestMapping的请求设置 1.3.2.1 方法11.3.2.2 方法2 二、Postman介绍 2.1 创建请求2.2 界面如下&#xff1a;2.3 传参介绍 一、Spring Web MVC简介 官方文档介绍&#xff…...

《解锁GANs黑科技:打造影视游戏的逼真3D模型》

在游戏与影视制作领域&#xff0c;逼真的3D模型是构建沉浸式虚拟世界的关键要素。从游戏中栩栩如生的角色形象&#xff0c;到影视里震撼人心的宏大场景&#xff0c;高品质3D模型的重要性不言而喻。随着人工智能技术的飞速发展&#xff0c;生成对抗网络&#xff08;GANs&#xf…...

【大数据技术】词频统计样例(hadoop+mapreduce+yarn)

词频统计(hadoop+mapreduce+yarn) 搭建完全分布式高可用大数据集群(VMware+CentOS+FinalShell) 搭建完全分布式高可用大数据集群(Hadoop+MapReduce+Yarn) 在阅读本文前,请确保已经阅读过以上两篇文章,成功搭建了Hadoop+MapReduce+Yarn的大数据集群环境。 写在前面 Wo…...

deepseek与openai关系

‌DeepSeek与OpenAI之间的关系主要体现在技术竞争和合作的可能性上。‌ 首先&#xff0c;DeepSeek是由中国的深度求索公司开发的&#xff0c;成立于2023年&#xff0c;专注于人工智能技术研发。其大模型DeepSeek-R1在数学、代码、自然语言推理等任务上的性能能够比肩OpenAI的G…...

51页精品PPT | 数据中台与数据治理服务及案例

案例的核心内容围绕数据中台与数据治理服务展开&#xff0c;详细介绍了数据治理的整体方法论、数据中台的建设路径以及如何通过数据治理和数据中台提升业务效率和数据质量。本案例强调了数据治理的重要性&#xff0c;包括数据标准、数据质量、数据安全等方面的管理&#xff0c;…...

使用 cipher /w 清除磁盘删除残留数据(Windows) - 随笔

cipher命令是Windows 系统自带的一个用于管理文件加密和磁盘数据清除的工具。通过 cipher /w 命令&#xff0c;可以清除磁盘上已删除文件的残留数据&#xff0c;确保这些数据无法被恢复。以下是一个简易的批处理脚本&#xff0c;用于清除指定磁盘上的加密数据。 echo off :: 清…...

RuntimeWarning: invalid value encountered in sqrt

代码出处&#xff1a; GitHub - wangsen1312/joints2smpl: fit smpl parameters model using 3D joints RuntimeWarning: invalid value encountered in sqrt 你可以通过以下几种方式解决这个问题&#xff1a; 1. 检查负值或零行列式 确保协方差矩阵是正半定的&#xff0c;这…...

3步打造C# API安全密盾

引言&#xff1a;API 安全的重要性 在数字化浪潮中&#xff0c;应用程序编程接口&#xff08;API&#xff09;已成为不同软件系统之间通信和数据交互的关键桥梁。无论是企业内部的微服务架构&#xff0c;还是面向外部用户的在线服务&#xff0c;API 都承担着数据传输和业务逻辑…...

项目实操:windows批处理拉取git库和处理目录、文件

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…...

接入 deepseek 实现AI智能问诊

1. 准备工作 注册 DeepSeek 账号 前往 DeepSeek 官网 注册账号并获取 API Key。 创建 UniApp 项目 使用 HBuilderX 创建一个新的 UniApp 项目&#xff08;选择 Vue3 或 Vue2 模板&#xff09;。 安装依赖 如果需要在 UniApp 中使用 HTTP 请求&#xff0c;推荐使用 uni.requ…...

ubuntu22.04源码编译mysql8.0.X详细流程【由deepseek提供】

以下是在 Ubuntu 22.04 上从源代码编译安装 MySQL 8.0.X&#xff08;以 MySQL 8.0.37 为例&#xff09;的详细操作流程&#xff1a; 一、准备工作 1. 更新系统 sudo apt update && sudo apt upgrade -y sudo apt install -y build-essential cmake pkg-config libssl…...

富唯智能复合机器人拓展工业新维度

富唯智能复合机器人是富唯智能倾力打造的一款集高度自动化、智能化和多功能性于一体的机器人。它融合了机械、电子、计算机、传感器等多个领域的前沿技术&#xff0c;通过精密的算法和控制系统&#xff0c;实现了对复杂生产环境的快速适应和高效作业。 富唯智能复合机器人的特点…...

【2】高并发导出场景下,服务器性能瓶颈优化方案-异步导出

Java 异步导出是一种在处理大量数据或复杂任务时优化性能和用户体验的重要技术。 1. 异步导出的优势 异步导出是指将导出操作从主线程中分离出来&#xff0c;通过后台线程或异步任务完成数据处理和文件生成。这种方式可以显著减少用户等待时间&#xff0c;避免系统阻塞&#x…...

verdi 查看覆盖率

点击Tools -> Coverage&#xff0c;会出现一个Verdi:vdCoverage:1页面点击File->Open/Add Database, 会出现一个 Open/Add Coverage Database页面&#xff0c; 在Design Hierarchy/Testbench Location 中输入 vdb路径点击… &#xff0c; 会出现当前路径下的文件&#xf…...

【React】路由处理的常见坑与解决方法,React Router 的动态路由与懒加载问题

在使用 React Router 时,动态路由和懒加载是非常常见的需求,但也可能会遇到一些坑。以下是常见问题以及对应的解决方法。 一、React Router 动态路由常见问题 1. 动态路由匹配问题 动态路由通常通过 :param 定义路径参数,但如果路径参数与静态路由有重叠,可能会导致匹配问…...

OKHttp拦截器解析

OKHttp涉及到拦截器大概的执行步骤为&#xff1a; 1.通过newCall生成RealCall对象 具体代码如下&#xff1a; Override public Call newCall(Request request) {return new RealCall(this, request, false /* for web socket */);}2.调用Call的execute方法 当然这也可以是执…...

顺序表和链表

线性表 线性表&#xff08;linear list&#xff09;是n 个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构。 常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。但是在物…...

若依框架使用(低级)

克隆源码 浏览器搜索若依&#xff0c;选择 RuoYi-Vue RuoYi-Vue RuoYi-Vue 重要的事情说三遍&#xff0c;进入gitee 下面这个页面&#xff08;注意红色框起来的部分&#xff09; 进入Gitee进行下载 我下载的是最新的springboot3 下载好后我们可以选择一个文件夹&#xff0…...