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

C++多线程函数介绍

1.C++11前没有线程库问题

对于多线程操作,Linux选择使用POSIX标准,而windows没有选择POSIX标准,自己设计了一套API和系统调用,叫Win32 API,就跟Linux存在标准差异,在Linux的代码移植到Windows就可能运行不了。

要保证兼容性,就需要借助条件编译,实现两份代码,根据不同平台执行对应的代码。

// 确保平台兼容性
#ifdef __WIN_32__
    CreateThread // Windows 中创建线程的接口
    // ...
#else
    pthread_create // Linux 中创建线程的接口
    // ...
#endif

C++11后,加入了线程库标准,包含了线程,互斥锁,条件变量等常用线程操作,不用依赖第三方库,使用线程库编写的代码可以在不同环境下运行。

2.C++多线程

并发与并行概念

 

并发是指两个或者多个事件在同一时间间隔发生,并发是针对单核CPU提出的,在同一CPU上的多个事件。

并行是指多个事件在同一时间发生 ,是针对多核CPU提出的,在不同CPU上的多个事件。

线程库--thread

线程对象构造

 1.默认构造函数

thread() noexcept;

创建了一个空的线程对象,不启动任何线程,不会抛出异常

2.模板构造函数

 template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);

Fn是一个可调用对象,可以是函数指针,函数对象或者lambda表达式

Args是传递给Fn的参数列表

explicit关键字表示这个构造函数显式的,防止隐式转换

移动构造函数

thread (thread&& x) noexcept;

 用于移动一个线程对象,接收一个右值引用thread&& x,表示从另一个线程对象x窃取线程资源

无参构造

无参数构造出来线程对象,它不会关联任何线程函数,不会启动任何线程。

thread t1;

因为有移动赋值函数,所以创建空线程可以窃取传参匿名线程对象资源。

带可变参数的构造

三种形式创建线程执行任务

需要休眠函数,不然结果会混乱,因为式并发执行任务,往显示器(公共资源)写入信息。

#include<iostream>
#include<algorithm>
#include<mutex>
#include<Windows.h>
#include<thread>
#include<condition_variable>
using namespace std;void func1(int start, int end)
{for (int i = start; i <= end; i++){cout << i << " ";}cout << endl;
}struct My_class
{void operator()(int start, int end){for (int i = start; i <= end; i++){cout << i << " ";}cout << endl;}
};int main()
{//函数指针thread t1(func1, 1, 10);Sleep(1);//仿函数(函数对象)thread t2(My_class(), 10, 20);Sleep(1);//lambda表达式thread t3([](const string& str) -> void {cout << str << endl; },"I am thread-3");t1.join();t2.join();t3.join();
}

 

注意:thread类是禁止拷贝的,不允许拷贝构造和拷贝赋值,但是可以移动构造和移动赋值,可以将一个线程对象关联状态转移给其它线程对象。

这里传函数名字,实际是传函数指针类型,而thread构造函数有模板参数,虽然是&&但是只有传过去的类型也是&&的才会是右值引用,不然就是左值引用,引用折叠规定。

例:传递函数指针

当你传递一个函数指针给std::thread的构造函数时,例如:

cpp复制

void func() {}
std::thread t(func);
  • func 是一个函数名,它是一个左值。

  • 根据引用折叠规则,F&& 在这种情况下会折叠为 F&,因为func是一个左值。

  • 因此,func作为左值被传递给std::thread的构造函数,它被绑定到一个左值引用上。

示例:传递函数对象

如果你传递一个函数对象或lambda表达式,例如:

cpp复制

std::thread t([]() { std::cout << "Hello" << std::endl; });
  • 这里的lambda表达式是一个右值。

  • 根据引用折叠规则,F&& 在这种情况下会折叠为 F&&,因为lambda表达式是一个右值。

  • 因此,lambda表达式作为右值被完美转发到std::thread的构造函数。

 

3.thread类的成员函数

1.join

  • 功能:等待一个线程完成。如果该线程还未执行完毕,则当前线程(一般是主线程)将被阻塞,直到该线程执行完成,主线程才会继续执行。

2.joinable

  • 功能:判断线程是否可以执行join()函数,返回truefalse

  • 用法if (t.joinable()) { t.join(); } 其中tstd::thread对象。

3.detach

  • 功能:将当前线程与创建的线程分离,使它们分别运行,当分离的线程执行完毕后,系统会自动回收其资源。如果一个线程被分离了,就不能再使用join()函数了,因为线程已经无法被联接了。

  • 用法t.detach(); 其中tstd::thread对象。

4.get_id

  • 功能:获取该线程的id

  • 用法std::thread::id t_id = t.get_id(); 其中tstd::thread对象。

5.swap

  • 功能:将两个线程对象关联线程的状态进行交换。

  • 用法t1.swap(t2); 其中t1t2std::thread对象。

join和joinable

joinable函数可以用于判断线程是否有效。

线程无效:采用无参构造的线程对象;线程对象的状态已经转移给其它线程对象;线程调用join或者detach。

代码示例

#include<iostream>
#include<algorithm>
#include<mutex>
#include<Windows.h>
#include<thread>
#include<condition_variable>
using namespace std;void Print()
{cout << "Hello from thread" << endl;}int main()
{thread t1(Print);Sleep(1);if (t1.joinable()){cout << "Thread is joinable" << endl;}t1.join();if (t1.joinable()){cout << "Thread is joinable" << endl;}else{cout << "Thread isn't joinable" << endl;}return 0;
}

代码解释

上面代码,先创建线程执行,延时为了让打印执行完,然后用joinable函数判断线程是否结束,没有执行join函数就还是存在,join函数执行后,线程结束资源回收,再去判断线程的状态就是结束了。

代码示例

#include<iostream>
#include<algorithm>
#include<mutex>
#include<Windows.h>
#include<thread>
#include<condition_variable>
using namespace std;void func()
{for (int i = 0; i <= 5; i++){cout << "线程执行中" << endl;this_thread::sleep_for(chrono::seconds(1));}cout << "线程结束" << endl;
}int main()
{thread t1(func);t1.detach();cout << "主线程继续执行" << endl;this_thread::sleep_for(chrono::seconds(7));cout << "主线程结束" << endl;return 0;
}

 代码解释

先执行线程函数,打印六次每次间隔1秒,因为执行了分离函数detach,所以主线程就会执行自己的代码,因为主线程结束了,线程也会跟着结束,所以主函数延时等待线程执行完才结束。

4.this_thread类

  1. get_id

    • 功能:获取当前线程的唯一标识符(ID)。

    • 用法std::thread::id id = std::this_thread::get_id();

    • 说明:每个线程都有一个唯一的ID,这个ID可以用来识别和区分不同的线程。

  2. sleep_for

    • 功能:使当前线程休眠一个指定的时间段。

    • 用法std::this_thread::sleep_for(std::chrono::milliseconds(500));

    • 说明:这个函数接受一个时间长度作为参数,单位可以是秒、毫秒等。线程会休眠指定的时间长度。

  3. sleep_until

    • 功能:使当前线程休眠直到指定的具体时间点。

    • 用法std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(5));

    • 说明:这个函数接受一个时间点作为参数,线程会休眠直到达到这个时间点。

  4. yield

    • 功能:使当前线程“放弃”执行,让操作系统调度另一个线程继续执行。

    • 用法std::this_thread::yield();

    • 说明:这个函数不会使线程休眠,而是让操作系统有机会调度其他线程。当前线程可能会在下一次调度时再次获得执行机会。

get_id与上面的thread类的不一样,thread类的get_id需要对象.get_id(),而这个可以直接this_thread::get_id()

代码示例

#include<iostream>
#include<algorithm>
#include<mutex>
#include<Windows.h>
#include<thread>
#include<condition_variable>
using namespace std;void func()
{cout << "Thread ID" << std::this_thread::get_id() << endl;
}int main()
{thread t1(func);Sleep(1);thread t2(func);Sleep(1);cout << "Main thread ID" << std::this_thread::get_id() << endl;t1.join();t2.join();return 0;
}

 sleep_for和sleep_until

sleep_until表示休眠一个绝对时间,比如线程运行结束后,休眠到某个具体的时间点(明天八点)继续运行,sleep_for是让线程休眠一个相对时间(休眠3秒)

相对时间:时,分,秒,毫秒等,这些单位包含在chrono类中。

 

代码示例

#include<mutex>
#include<Windows.h>
#include<thread>
#include<condition_variable>
#include<vector>
using namespace std;int main()
{vector<thread> v(5);for (int i = 0; i < 5; i++){v[i] = thread([]()->void{for (int i = 0; i < 10; i++){auto id = this_thread::get_id();cout << "我是线程" << id << "正在运行" << endl;this_thread::sleep_for(chrono::milliseconds(200));}});}for (auto& x : v){x.join();}return 0;}

线程函数传参数问题

线程函数的参数使拷贝的方式拷贝到线程栈空间中,使用引用传参数,在线程内部修改这个引用值也不会改变(在传过去的线程打印值还是原来的),因为实际引用的是线程栈中的拷贝,而不是线程函数的形参。

void add(int& num)
{num++;
}
int main()
{int num = 0;thread t(add, num);t.join();cout << num << endl; //0return 0;
}

通过线程函数形参改变外部的实参

#include<iostream>
#include<algorithm>
#include<mutex>
#include<Windows.h>
#include<thread>
#include<condition_variable>
#include<vector>
using namespace std;void func1(int& x)
{x += 10;
}void func2(int* x)
{*x += 10;
}int main()
{int a = 10;//方案一//如果想要通过形参改变外部实参时,必须借助std::ref()函数std::thread t1(func1, std::ref(a));t1.join();std::cout << a << std::endl;//方案二std::thread t2(func2, &a);t2.join();cout << a << endl;//方案三std::thread t3([&a]() {a += 10; });t3.join();cout << a << endl;
}

5.互斥量库-mutex

锁是一种机制,用来确保同一时刻只有一个线程可以访问共享资源。通过使用锁,可以防止多个线程同时修改共享资源,从而保证数据的一致性和正确性。

线程拥有自己独立的栈结构,但对于全局变量等临界资源,是直接被多个线程共享的。

int g_val = 0;void Func(int n)
{cout << "&g_val: " << &g_val << " &n: " << &n << endl << endl;
}int main()
{int n = 10;thread t1(Func, n);thread t2(Func, n);t1.join();t2.join();return 0;
}

g_val的地址一样,而局部变量的地址不一样,就说明栈区不是同一个,处于线程的独立栈。

6.标准库提供的四种互斥锁

1.std::mutex

mutex锁是基本的互斥量,mutex之间不能进行拷贝,也不能进行移动。

  1. lock

    • 功能:对互斥量进行加锁。

    • 用法mutex.lock();

    • 说明:调用lock函数会阻塞当前线程,直到互斥量被成功锁定。如果互斥量已经被其他线程锁定,调用lock的线程将会等待,直到互斥量被解锁。

  2. try_lock

    • 功能:尝试对互斥量进行加锁。

    • 用法bool success = mutex.try_lock();

    • 说明:与lock不同,try_lock不会阻塞当前线程。如果互斥量已经被其他线程锁定,try_lock会立即返回false,否则返回true表示成功锁定互斥量。

  3. unlock

    • 功能:对互斥量进行解锁,释放互斥量的所有权。

    • 用法mutex.unlock();

    • 说明:调用unlock函数会释放当前线程持有的互斥量锁。之后,其他线程可以尝试通过locktry_lock来获取互斥量的锁。需要注意的是,只有拥有互斥量锁的线程才能调用unlock函数。

代码示例

#include<iostream>
#include<algorithm>
#include<mutex>
#include<Windows.h>
#include<thread>
#include<condition_variable>
#include<vector>
#include<mutex>
using namespace std;int g_val = 0;
mutex mtx;void func(int n)
{mtx.lock();while (n--){g_val++;}mtx.unlock();
}int main()
{int n = 20000;thread t1(func, n);thread t2(func, n);t1.join();t2.join();cout << "g_val:" <<g_val<< endl;return 0;
}

并行与串行

互斥锁的加锁,解锁位置不同,就会有不同的效果,锁加在while的外面,则先拿到锁的线程就会先执行完任务,就是串行操作。锁加在while里面,则是两个线程一起执行任务,就是并行操作。

而在这个代码中,把锁放在外面是快的,因为锁在里面,临界区很小,就会频繁申请锁和释放锁,效率低下,最好把临界区的大小适当。

2.std::recursive_mutex

recursive_mutex递归互斥锁,这把锁主要用来递归加锁的场景中。

代码示例

 这个代码就会造成死锁,因为申请锁后,执行递归函数,有重新申请锁,而锁并没有释放,就会阻塞在这里,造成死锁。把锁换成递归时用的锁就可以解决。(递归的锁会判断当前的函数是否跟递归前的函数是否一样,一样就可以访问临界区,而不会阻塞)

// 普通互斥锁
mutex mtx;void func(int n)
{if (n == 0)return;mtx.lock();n--;func(n);mtx.unlock();
}int main()
{int n = 1000;thread t1(func, n);thread t2(func, n);t1.join();t2.join();return 0;
}

3.std::timed_mutex

timed_mutex时间互斥锁,这把锁新增了定时解锁的功能,可以把程序运行指定时间后,自动解锁,如果锁没有解开。

try_lock_for是按照相对时间自动解锁,而try_lock_until则是按照绝对时间解锁

4.std::recursive_timed_mutex

这个锁是递归时间互斥锁,可以解决递归以及定时解锁。

7.RAII风格的锁

手动加锁,解锁可能会出现死锁问题,引进的异常处理,临界区遇到异常就跳出去执行catch了,锁就没有被解开,就导致死锁问题。

#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;void dangerousFunction(int id) 
{// 手动加锁mtx.lock();std::cout << "Thread " << id << " is running." << std::endl;// 模拟一个异常情况,没有解锁就退出if (id == 1) {throw std::runtime_error("Thread 1 encountered an error!");}// 手动解锁(如果有异常发生,这行代码不会执行)mtx.unlock();
}int main() {try {std::thread t1(dangerousFunction, 1);std::thread t2(dangerousFunction, 2);t1.join();t2.join();} catch (const std::exception &e) {std::cerr << "Exception caught: " << e.what() << std::endl;}return 0;
}

RAII风格编写代码

#include<iostream>
#include<algorithm>
#include<mutex>
#include<Windows.h>
#include<thread>
#include<condition_variable>
#include<vector>
#include<mutex>
using namespace std;std::mutex mtx;void func(int id)
{try{std::lock_guard<std::mutex> lock(mtx);std::cout << "Thread" << id << " is running" << std::endl;if (id == 1){throw std::runtime_error("Thread error");}}catch (const std::exception& e){std::cerr << "Exception caught in thread" << id << ":" << e.what() << std::endl;}
}int main()
{try{std::thread t1(func, 1);std::thread t2(func, 2);t1.join();t2.join();}catch(const std::exception& e){std::cerr << "Exception caught:" << e.what() << std::endl;}return 0;
}

lock_guard

std::lock_guard是C++是标准库的一个模板类,用于实现资源的自动加锁和解锁。基于RALL设计理念,能够确保在作用域结束时自动释放锁资源。

 

std::lock_guard的主要特点

1.自动加锁: 在创建std::lock_guard对象时,会立即对指定的互斥量进行加锁操作。这样可以确保在进入作用域后,互斥量已经被锁定,避免了并发访问资源的竞争条件。
2.自动解锁:std::lock_guard对象在作用域结束时,会自动释放互斥量。无论作用域是通过正常的流程结束、异常抛出还是使用return语句提前返回,std::lock_guard都能保证互斥量被正确解锁,避免了资源泄漏和死锁的风险。
3.适用于局部锁定: 由于std::lock_guard是通过栈上的对象实现的,因此适用于在局部范围内锁定互斥量。当超出std::lock_guard对象的作用域时,互斥量会自动解锁,释放控制权。

 

unique_lock

std::unique_lock是C++标准库中的一个模板类,用于实现更加灵活的互斥量的加锁和解锁操作。

std::unqiue_lock特点

1.可以自动加锁和解锁,在创建对象时立即对指定的互斥量进行加锁操作,确保互斥量被锁定。

2.更加灵活加锁和解锁,可以自动加锁和解锁,也可以手动解锁和解锁。

3.可以延迟加锁和条件变量,std::unqiue_lock支持延迟加锁的功能,可以在锁没申请下创建对象,加锁后就直接管理这个锁。

代码示例

#include<iostream>
#include<algorithm>
#include<mutex>
#include<Windows.h>
#include<thread>
#include<condition_variable>
#include<vector>
#include<mutex>
using namespace std;std::mutex mtx;void func1()
{std::unique_lock<std::mutex> lock(mtx);std::cout << "Thread running" << std::endl;//手动解锁加锁lock.unlock();lock.lock();}//结束时自动释放锁int main()
{std::thread t1(func1);t1.join();return 0;
}

相关文章:

C++多线程函数介绍

1.C11前没有线程库问题 对于多线程操作&#xff0c;Linux选择使用POSIX标准&#xff0c;而windows没有选择POSIX标准&#xff0c;自己设计了一套API和系统调用&#xff0c;叫Win32 API&#xff0c;就跟Linux存在标准差异&#xff0c;在Linux的代码移植到Windows就可能运行不了…...

图解AUTOSAR_SWS_LINTransceiverDriver

AUTOSAR LIN收发器驱动(LinTransceiverDriver)详解 AUTOSAR通信栈物理层组件详细解析 目录 AUTOSAR LIN收发器驱动(LinTransceiverDriver)详解 目录1. 概述 1.1. LIN收发器驱动的作用1.2. 在AUTOSAR架构中的位置2. 架构设计 2.1. 模块结构2.2. 组件关系2.3. 接口定义3. 状态管理…...

vue-element-admin 组件没有展示在中间部分

解决办法&#xff1a; router index.ts 中新增 要展示的组件的 import type { App } from "vue"; import { createRouter, createWebHashHistory, type RouteRecordRaw } from "vue-router";export const Layout () > import("/layout/index.…...

当机器学习遇见购物车分析:FP-Growth算法全解析

一、引言&#xff1a;购物篮里的秘密 想象一下&#xff0c;你是一家超市的数据分析师&#xff0c;看着每天成千上万的购物小票&#xff0c;你是否好奇&#xff1a;顾客们买面包的时候&#xff0c;是不是也经常顺手带上牛奶&#xff1f;买啤酒的人&#xff0c;会不会也喜欢买尿…...

OCR迁移

一、环境 操作系统&#xff1a;Centos57.6 数据库版本&#xff1a;12.2.0.1 场景&#xff1a;将OCR信息从DATA磁盘组迁移到OCR磁盘组 二、操作步骤 1.查看可用空盘 set lin 200 set pagesize 200 col DGNAME format a15 col DISKNAME format a15 col PATH format a20 col N…...

【架构艺术】Go大仓monorepo中使用wire做依赖注入的经验

在先前的文章当中&#xff0c;笔者分享了一套简洁的go微服务monorepo代码架构的实现&#xff0c;主要解决中小团队协同开发微服务集群的代码架构组织问题。但是在实际代码开发过程中&#xff0c;怎么组织不同的业务服务service实例&#xff0c;就成了比较棘手的问题。 为什么会…...

生活电子常识--删除谷歌浏览器搜索记录

前言 谷歌浏览器会记录浏览器历史搜索,如果不希望看到越来越多的搜索记录,可以如下设置 解决 设置-隐私-自动填充表单 这个和浏览器记录的密码没有关系,可以放心删除...

每日一题(小白)模拟娱乐篇13

今天题目比较简单&#xff0c;直接分析。小蓝想知道2024这个数字中有几个1&#xff0c;计算机组成学习好的同学肯定可以直接长除法或者瞪眼法得出答案&#xff1a; 202411111101000&#xff08;B&#xff09;也就是说2024中有一共有六个1 接下来用代码实现 &#xff0c;我们也…...

码曰编程大模型-学编程的好工具

码曰&#xff08;yue&#xff09;&#xff0c;一款编程垂直领域的AI大模型&#xff0c;是基于包括DeepSeek在内的多款国产大模型为底座&#xff0c;依托于Dotcpp系统大量的编程代码数据&#xff0c;且借助RAG数据检索增强等技术综合实现的出色、好用的编程垂直领域AI大模型&…...

Linux(CentOS 7) 部署 redis 集群

下载redis Downloads - Redis (官网页都是介绍的最新版&#xff0c;我观察目前出现了redis 和 redis Stack) 因我的旧环境是 CentOS 7&#xff0c;redis最新版已经不在支持&#xff0c;所以示例安装最常用的7.0.x 这里直接附上各个版本下载连接 小伙伴们就不需要在自己寻找下载…...

NVIDIA AgentIQ 详细介绍

NVIDIA AgentIQ 详细介绍 1. 引言 NVIDIA AgentIQ 是一个灵活的库&#xff0c;旨在将企业代理&#xff08;无论使用何种框架&#xff09;与各种数据源和工具无缝集成。通过将代理、工具和代理工作流视为简单的函数调用&#xff0c;AgentIQ 实现了真正的可组合性&#xff1a;一…...

在CPU服务器上部署Ollama和Dify的过程记录

在本指南中&#xff0c;我将详细介绍如何在CPU服务器上安装和配置Ollama模型服务和Dify平台&#xff0c;以及如何利用Docker实现这些服务的高效部署和迁移。本文分为三大部分&#xff1a;Ollama部署、Dify环境配置和Docker环境管理&#xff0c;适合需要在本地或私有环境中运行A…...

小程序API —— 57 拓展 - 增强 scroll-view

目录 1. 配置基本信息2. 实现上拉加载更多功能3. 实现快速回到顶部功能4. 实现下拉刷新功能 scroll-view 组件功能非常强大&#xff0c;这里使用 scroll-view 实现上拉加载和下拉刷新功能&#xff1b; 下面使用微信开发者工具来演示一下具体用法&#xff1a; 1. 配置基本信息 …...

P3613 【深基15.例2】寄包柜

#include<bits/stdc.h> using namespace std; int n,q; map<int, map<int, int>>a;//二维映射 int main(){cin>>n>>q;while(q--){int b,i,j,k;//i为第几个柜子&#xff0c;j为第几个柜包&#xff0c;k为要存入的物品cin>>b>>i>&…...

MIMO预编码与检测算法的对比

在MIMO系统中&#xff0c;预编码&#xff08;发送端处理&#xff09;和检测算法&#xff08;接收端处理&#xff09;的核心公式及其作用对比如下&#xff1a; 1. 预编码算法&#xff08;发送端&#xff09; 预编码的目标是通过对发送信号进行预处理&#xff0c;优化空间复用或…...

AI复活能成为持续的生意吗?

随着人工智能技术的飞速发展,AI复活——这一曾经只存在于科幻电影中的概念,如今已悄然走进现实。通过AI技术,人们可以模拟逝去亲人的声音、面容,甚至创造出与他们互动的虚拟形象,以寄托哀思、缓解痛苦。然而,当这种技术被商业化,成为一门生意时,我们不禁要问:AI复活真…...

Keil 5 找不到编译器 Missing:Compiler Version 5 的解决方法

用到自记&#xff1a; 下载地址&#xff1a; Keil5 MDK541.zip ​编辑https://pan.baidu.com/s/1bOPsuVZhD_Wj4RJS90Mbtg?pwdMDK5 问题描述 没有找到 compiler version5 &#xff1a; 1. 下载 Arm Compiler 5 也可以直接点击下载文章开头的文件。 2. 安装 直接安装在KEI…...

Flutter 手搓日期选择

时间选择器&#xff1a; 时间段选择 在实际开发过程中还是挺常见的。Flutter 本身自带选 时间选择器器 CupertinoDatePicker&#xff0c;样式也是可以定义的&#xff0c;但是他 只提供三种时间的选择 自定义有局限性。后来开了一下 代码&#xff0c;实际上 内部使用的是 Cuper…...

《JVM考古现场(十六):太初奇点——从普朗克常量到宇宙弦的编译风暴》

开篇&#xff1a;量子泡沫编译器的创世大爆炸 "当Project Genesis的真空涨落算法撕裂量子泡沫&#xff0c;当意识编译器重写宇宙基本常数&#xff0c;我们将在奇点编译中见证&#xff1a;从JVM字节码到宇宙大爆炸的终极创世&#xff01;诸君请备好量子护目镜&#xff0c;…...

MySQL学习笔记——MySQL下载安装配置(一)

目录 1. MySQL概述 1.1 数据库相关概念 1.2 MySQL数据库 1.2.1 版本 1.2.2 下载 2. 安装 3. 配置 4. 启动停止 5. 客户端连接 1. MySQL概述 1.1 数据库相关概念 在这一部分&#xff0c;我们先来讲解三个概念&#xff1a;数据库、数据库管理系统、 SQL 。 而目前主流…...

TortoiseGit多账号切换配置

前言 之前配置好的都是&#xff0c;TortoiseGit与Gitee之间的提交&#xff0c;突然有需求要在GitHub上提交&#xff0c;于是在参考网上方案和TortoiseGit的帮助手册后&#xff0c;便有了此文。由于GitHub已经配置完成&#xff0c;所以下述以配置Gitee为例。因为之前是单账号使用…...

数据一键导出为 Excel 文件

引言 在 Web 应用开发中&#xff0c;数据导出是一个常见且重要的功能。用户常常需要将网页上展示的数据以文件形式保存下来&#xff0c;以便后续分析、处理或分享。本文将详细介绍如何使用 HTML、CSS 和 JavaScript&#xff08;结合 jQuery 库&#xff09;实现一个简单的数据导…...

FPGA——状态机实现流水灯

文章目录 一、状态机1.1 分类1.2 写法 二、状态机思想编写LED流水灯三、运行结果总结参考资料 一、状态机 FPGA不同于CPU的一点特点就是CPU是顺序执行的&#xff0c;而FPGA是同步执行&#xff08;并行&#xff09;的。那么FPGA如何处理明显具有时间上先后顺序的事件呢&#xf…...

linux paste 命令

paste 是 Linux 中一个用于水平合并文件内容的命令行工具&#xff0c;它将多个文件的对应行以并行方式拼接&#xff0c;默认用制表符&#xff08;Tab&#xff09;分隔。 1. 基本语法 paste [选项] 文件1 文件2 ... 2. 常用选项 选项说明-d指定拼接后的分隔符&#xff08;默…...

ffmpeg常见命令2

文章目录 1. **提取音视频数据&#xff08;Extract Audio/Video Data&#xff09;**提取音频&#xff1a;提取视频&#xff1a; 2. **提取像素数据&#xff08;Extract Pixel Data&#xff09;**3. **命令转封装&#xff08;Container Format Conversion&#xff09;**转换视频…...

FPGA——FPGA状态机实现流水灯

一、引言 在FPGA开发中&#xff0c;状态机是一种重要的设计工具&#xff0c;用于处理具有时间顺序的事件。本文将详细介绍如何使用状态机实现一个LED流水灯的效果。 二、状态机概述 状态机&#xff08;FSM&#xff09;是一种行为模型&#xff0c;用于表示系统在不同状态下的…...

鸿蒙 ——选择相册图片保存到应用

photoAccessHelper // entry/src/main/ets/utils/file.ets import { fileIo } from kit.CoreFileKit; import { photoAccessHelper } from kit.MediaLibraryKit; import { bundleManager } from kit.AbilityKit;// 应用在本设备内部存储上通用的存放默认长期保存的文件路径&am…...

消息队列之-Kafka

目录 消息队列消息队列的使用场景初识KafkaKafka设计思想Kafka消息结构消息发送消息消费 Kafka高可用消息备份机制1. 基本原理2. ISR&#xff08;In-Sync Replicas&#xff09;3. ACK&#xff08;Acknowledgements&#xff09;4. LEO&#xff08;Log End Offset&#xff09;5. …...

财务税务域——企业税务系统设计

摘要 本文主要探讨企业税务系统设计&#xff0c;涵盖企业税收管理背景、税收业务流程、系统设计架构与功能、外部系统对接以及相关问题。企业税务的背景包括税收制度的形成、企业税务的必然性、全球化影响&#xff0c;其核心目标是合规性、优化税负、风险管理与战略支持&#…...

状态机思想编程

文章目录 一、状态机思想重新写一个 LED流水灯的FPGA代码1.状态机的概念2.代码设计 二、CPLD和FPGA芯片的主要技术区别与适用场合三、hdlbitsFPGA教程网站上进行学习 一、状态机思想重新写一个 LED流水灯的FPGA代码 1.状态机的概念 状态机的基本要素有 3 个&#xff0c;其实我…...

TiDB 数据库8.1版本编译及部署

本文介绍 TiDB 数据库8.1版本的编译和部署。 背景 自前年&#xff08;2023年&#xff09;接触了TiDB后&#xff0c;做了简单的测试就直接使用了。因一些事务的不连续性&#xff0c;导致部分成果没有保存&#xff0c;去年年底又重新拾起&#xff0c;使用了新的LTS版本&#xff…...

基于 docker 的 Xinference 全流程部署指南

Xorbits Inference (Xinference) 是一个开源平台&#xff0c;用于简化各种 AI 模型的运行和集成。借助 Xinference&#xff0c;您可以使用任何开源 LLM、嵌入模型和多模态模型在云端或本地环境中运行推理&#xff0c;并创建强大的 AI 应用。 一、下载代码 请在控制台下面执行…...

【2022】【论文笔记】基于相变材料的光学激活的、用于THz光束操作的编码超表面——

前言 类型 太赫兹 + 超表面 太赫兹 + 超表面 太赫兹+超表面 期刊 A D V A N C E D    O P T I C A L    M A T E R I A L S ADVANCED \; OPTICAL \; MATERIALS...

MySQL系统库汇总

目录 简介 performance_schema 作用 分类 简单配置与使用 查看最近执行失败的SQL语句 查看最近的事务执行信息 sys系统库 作用 使用 查看慢SQL语句慢在哪 information_schema 作用 分类 应用 查看索引列的信息 mysql系统库 权限系统表 统计信息表 日志记录…...

【Kafka基础】Docker Compose快速部署Kafka单机环境

1 准备工作 1.1 安装Docker和Docker Compose Docker安装请参考&#xff1a; Docker入门指南&#xff1a;1分钟搞定安装 常用命令&#xff0c;轻松入门容器化&#xff01;-CSDN博客 Docker Compose安装请参考&#xff1a; 【docker compose入门指南】安装与常用命令参数全解析…...

【51单片机】2-5【I/O口】433无线收发模块控制继电器

1.硬件 51最小系统继电器模块433无线收发模块 2.软件 #include "reg52.h"sbit D0_ON P1^2;//433无线收发模块的按键A sbit D1_OFF P1^3;//433无线收发模块的按键Bsbit switcher P1^1;//继电器void main() {//查询方式哪个按键被按下while(1){if(D0_ON 1)//收到…...

平台总线---深入分析

阅读引言&#xff1a;本文会从平台总线的介绍&#xff0c;注册平台设备和驱动&#xff0c; 源码分析&#xff0c; 总结五个部分展开&#xff0c; 源码分析platform放在了最后面。 目录 一、平台总线介绍 二、平台总线如何使用 三、平台总线是如何工作的 四、注册platform设…...

pyTorch框架:模型的子类写法--改进版二分类问题

目录 1.导包 2.加载数据 3.数据的特征工程 4.pytorch中最常用的一种创建模型的方式--子类写法 1.导包 import torch import pandas as pd import numpy as np import matplotlib.pyplot as plt2.加载数据 data pd.read_csv(./dataset/HR.csv)data.head() #查看数据的前…...

【python中级】解压whl文件内容

【python中级】解压whl文件内容 1.背景2.解压1.背景 【python中级】关于whl文件的说明 https://blog.csdn.net/jn10010537/article/details/146979236 补充以上博客: 在 旧版 setuptools 中(< v58),如果想生成 .whl,必须先pip install 安装 wheel 三方包! pip inst…...

【USRP】srsRAN 开源 4G 软件无线电套件

srsRAN 是SRS开发的开源 4G 软件无线电套件。 srsRAN套件包括&#xff1a; srsUE - 具有原型 5G 功能的全栈 SDR 4G UE 应用程序srsENB - 全栈 SDR 4G eNodeB 应用程序srsEPC——具有 MME、HSS 和 S/P-GW 的轻量级 4G 核心网络实现 安装系统 Ubuntu 20.04 USRP B210 sudo …...

LeetCode算法题(Go语言实现)_30

题目 给定单链表的头节点 head &#xff0c;将所有索引为奇数的节点和索引为偶数的节点分别组合在一起&#xff0c;然后返回重新排序的列表。 第一个节点的索引被认为是 奇数 &#xff0c; 第二个节点的索引为 偶数 &#xff0c;以此类推。 请注意&#xff0c;偶数组和奇数组内…...

生信入门:专栏概要与内容目录

文章目录 生信入门&#x1f4da; 核心内容模块基础概念入门序列联配算法高级算法与应用理论基础与数学方法基因组分析 生信入门 &#x1f525; 专栏简介 | 生信算法与实践指南 开启生物信息学的学习之旅 &#x1f31f; 为什么订阅本专栏&#xff1f; 循序渐进&#xff1a;从生…...

Matplotlib:数据可视化的艺术与科学

引言&#xff1a;让数据开口说话 在数据分析与机器学习领域&#xff0c;可视化是理解数据的重要桥梁。Matplotlib 作为 Python 最流行的绘图库&#xff0c;提供了从简单折线图到复杂 3D 图表的完整解决方案。本文将通过实际案例&#xff0c;带您从基础绘图到高级定制全面掌握 …...

线程共享数据所带来的安全性问题

笔记 import threading from threading import Thread import time tickte50 # 代表的是50张票def sale_ticket():global tickte# 每个排队窗口假设有100人for i in range(100): # 每个线程要执行100次循环if tickte>0:print(f{threading.current_thread().name}正在出售第…...

Redis核心机制-缓存、分布式锁

目录 缓存 缓存更新策略 定期生成 实时生成 缓存问题 缓存预热&#xff08;Cache preheating&#xff09; 缓存穿透&#xff08;Cache penetration&#xff09; 缓存雪崩&#xff08;Cache avalanche&#xff09; 缓存击穿&#xff08;Cache breakdown&#xff09; 分…...

Node.js中间件的5个注意事项

目录 1. 目录结构 2. 代码实现 注意事项 1&#xff1a;必须调用 next() 注意事项 2&#xff1a;中间件的执行顺序很重要 注意事项 3&#xff1a;局部中间件的使用 注意事项 4&#xff1a;统一处理 404 注意事项 5&#xff1a;使用错误处理中间件 3. 总结 在Node.js的Ex…...

软件学报 2024年 区块链论文 录用汇总 附pdf下载

Year&#xff1a;2024 1 Title: 带有预验证机制的区块链动态共识算法 Authors: Key words: 区块链;混合共识;预验证机制;动态共识;委员会腐败 Abstract: 委员会共识和混合共识通过选举委员会来代替全网节点完成区块验证, 可有效加快共识速度, 提高吞吐量, 但恶意攻击和收…...

从开发到上线:基于 Linux 云服务器的前后端分离项目部署实践(Vue + Node.js)

明白了&#xff0c;这次我们完全聚焦技术内容本身&#xff0c;不带明显广告语言&#xff0c;不插入链接&#xff0c;只在文末一个不显眼的地方轻描淡写提到“服务器用的是 zovps.com 的一台基础云主机”&#xff0c;整体文章保证原创、高质量、易审核、易分发&#xff0c;长度控…...

FastAPI-Cache2: 高效Python缓存库

FastAPI-Cache2是一个强大而灵活的Python缓存库&#xff0c;专为提升应用性能而设计。虽然其名称暗示与FastAPI框架的紧密集成&#xff0c;但实际上它可以在任何Python项目中使用&#xff0c;为开发者提供简单而高效的缓存解决方案。 在现代应用开发中&#xff0c;性能优化至关…...

提高:图论:强连通分量 图的遍历

时间限制 : 1 秒 内存限制 : 128 MB 给出 NN 个点&#xff0c;MM 条边的有向图&#xff0c;对于每个点 vv&#xff0c;求 A(v)A(v) 表示从点 vv 出发&#xff0c;能到达的编号最大的点。 输入 第 11 行 22 个整数 N,MN,M&#xff0c;表示点数和边数。 接下来 MM 行&#x…...