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

Linux:43线程封装与互斥lesson31

mmap文件映射视屏:待看...


目录

线程栈

代码证明:一个线程的数据,其他线程也可以访问

线程封装

简单封装,2.thread

Thread.hpp

Main.cc

 Makefile

结果:

​编辑

问题1:

问题2: lamba表达式

模版封装 3.thread_template

Thread.hpp

Main.cc

 Makefile

结果

​编辑

 线程局部存储4threadlocal

test.cc

Makefile

结果: 

添加:__thread

结果:

pthread_setname_np:设置线程的名字。

pthread_getname_np:用于获取线程的名称。

用2.thread进行修改 

 同步和互斥

5.mutex代码,加锁和解锁,见一下


线程栈

• 对于Linux进程或者说主线程,简单理解就是main函数的栈空间,在fork的时候,实际上就是复 制了⽗亲的 stack 空间地址,然后写时拷⻉(cow)以及动态增⻓。如果扩充超出该上限则栈溢出 会报段错误(发送段错误信号给该进程)。进程栈是唯⼀可以访问未映射⻚⽽不⼀定会发⽣段错 误⸺⸺超出扩充上限才报。

• 然⽽对于主线程⽣成的⼦线程⽽⾔,其 stack 将不再是向下⽣⻓的,⽽是事先固定下来的。线 程栈⼀般是调⽤glibc/uclibc等的 pthread 库接 pthread_create 创建的线程,在⽂件映 射区(或称之为共享区)。其中使⽤ mmap 系统调⽤,这个可以从 glibc 的

nptl/allocatestack.c 中的 allocate_stack 函数中看到:

mem = mmap (NULL, size, prot, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);

此调⽤中的 size 参数的获取很是复杂,你可以⼿⼯传⼊stack的⼤⼩,也可以使⽤默认的,⼀般⽽ ⾔就是默认的 8M 。这些都不重要,重要的是,这种stack不能动态增⻓,⼀旦⽤尽就没了,这是和 ⽣成进程的fork不同的地⽅。在glibc中通过mmap得到了stack之后,底层将调⽤ sys_clone 系 统调⽤:

对于⼦线程的 stack ,它其实是在进程的地址空间中map出来的⼀块内存区域,原则上是 线程私有的,但是同⼀个进程的所有线程⽣成的时候,是会浅拷⻉⽣成者的 task_struct 的很多 字段,如果愿意,其它线程也还是可以访问到的,于是⼀定要注意。


 每个线程都有自己的栈结构:

独立的上下文:有独立的PCB+TCP(用户层,pthread库内部)

独立的栈:每个线程都有自己的栈结构,要么是进程自己的要么是库中创建进程时mmap申请出来的。

结论:一个线程的数据,其他线程也可以访问:只要拿到对应的地址即可。

代码证明:一个线程的数据,其他线程也可以访问

//证明:一个线程的数据,其他线程也可以访问:只要拿到对应的地址即可。
#include <sched.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>int *p = nullptr;void *threadrun(void *args){int a = 123;p = &a;while(true) {sleep(1);}}int main(){pthread_t tid;pthread_create(&tid, nullptr, threadrun, nullptr);while(true){std::cout << "*p : " << *p << std::endl;sleep(1);}pthread_join(tid, nullptr);return 0;}

线程封装

线程ID:就是动态库。

线程的封装

以面向对象的形式把线程进行封装

计数器:进程编号: static uint32_t number = 0;

_name:线程名字
_tid:tid
_isdetach:是否被分分离。
_isrunning:是否正在运行,是否调用Start()

Start()线程开始/创建:
--创建线程,pthread_creat
--如果分离,那么就设置线程分离,pthreaddetach

EnableDetach():
是否分离。

Detach():
如果一个线程已经跑起来了,要把它设置为分离状态,用detach()

Enablerunning():
是否已经运行

Stop():停止进程
pthread_cancle
是运行状态才可以stop(),

Join():
如果是分离的那么就不可以Join()

Routine(),写在在public会报错,
因为Routine属于类内的成员函数,默认包含this指针???


_func()回调方法,static没有this指针 ,无法回调房钱成员,
解决:把thos指针传入Routine

简单封装,2.thread

Thread.hpp

#ifndef _THREAD_H_
#define _THREAD_H_
//一个头文件保护机制,防止头文件被重复包含
#include <iostream>
#include <string>
#include <pthread.h>
#include <cstdio>
#include <cstring>
#include <functional>namespace ThreadModlue{static uint32_t number = 1;class Thread{using func_t = std::function<void()>;// 添加模版的前身private:void Enabledetach(){std::cout<<"线程被分离了"<<std::endl;_isdetach = true;}void Enablerunning(){std::cout<<"线程正在运行"<<std::endl;_isrunning = true;}static void* Routine(void*args){//static,没有默认指针,需要在线程创建的时候,通过args传回this指针Thread* self = static_cast<Thread*>(args);//强转成Thread*类型self->Enablerunning();if(self->_isdetach){self->Enabledetach();}self->_func();//调用函数要加上()括号才可以调用return nullptr;}public:Thread(func_t func):_tid(0),_isdetach(false),_isrunning(false),_res(nullptr),_func(func){_name = "thread - " + std::to_string(number++);}void Detach(){if(_isdetach)return;if(_isrunning){pthread_detach(_tid);std::cout<<"线程分离成功"<<std::endl;Enabledetach();}}bool Start(){if(_isrunning)return false;//线程正在运行,不可再次启动int n = pthread_create(&_tid,nullptr,Routine,this);if( n != 0 ){std::cerr<<"创建线程错误"<<strerror(n)<<std::endl;return false;}else{std::cout<<"线程创建成功:"<<_name<<std::endl;return true;}}bool Stop(){if(_isrunning){int n = pthread_cancel(_tid);if(n != 0){std::cerr<<"线程停止错误:"<<strerror(n)<<std::endl;return false;}else{_isrunning = false;std::cout<<"线程停止:"<<_name<<std::endl;return true;}}}void Join(){if(_isdetach){std::cout<<"已经被分离的线程无法join"<<std::endl;return;}int n = pthread_join(_tid,&_res);if(n != 0){std::cerr<<"线程join错误:"<<strerror(n)<<std::endl;}else{std::cout << "线程join成功" << std::endl;}}private:pthread_t _tid;bool _isdetach;bool _isrunning;std::string _name;void* _res;func_t _func;};
}
#endif

Main.cc

#include "Thread.hpp"
#include <unistd.h>
#include <vector>using namespace ThreadModlue;int main(){Thread t([](){while(true){std::cout << "我是一个新线程: "<< std::endl; // 我的线程的名字是什么呀?debugsleep(1);}});t.Start();t.Detach();sleep(2);t.Stop();sleep(2);t.Join();return 0;
}

 Makefile

test_thread:Main.ccg++ -o $@ $^ -lpthread
.PHONY:clean
clean:rm -f test_thread

结果:

问题1:

在实现线程的封装过程中,Routine(),写在在public会报错,
因为Routine属于类内的成员函数,默认包含this指针???
这句话怎么理解 ???

static void* Routine(void*args){
//static,没有默认指针,需要在线程创建的时候,通过args传回this指针Thread* self = static_cast<Thread*>(args);//强转成Thread*类型self->Enablerunning();if(self->_isdetach){self->Enabledetach();}self->_func();//调用函数要加上()括号才可以调用return nullptr;}

pthread_create调用Routine函数,但是Routine没有默认的this指针,

那么就需要在pthread_create的第四个传入Routine的参数传入this指针作为参数才可以

问题2: lamba表达式

 Thread t([](){while(true){std::cout << "我是一个新线程: "<< std::endl; // 我的线程的名字是什么呀?debugsleep(1);}});

模版封装 3.thread_template

Thread.hpp

#ifndef _THREAD_H_
#define _THREAD_H_
//一个头文件保护机制,防止头文件被重复包含
#include <iostream>
#include <string>
#include <pthread.h>
#include <cstdio>
#include <cstring>
#include <functional>namespace ThreadModlue{static uint32_t number = 1;template<typename T>//这里设置模版类型class Thread{using func_t = std::function<void(T)>;// 添加模版的前身 + 模版添加需要传参数!!!private:void Enabledetach(){std::cout<<"线程被分离了"<<std::endl;_isdetach = true;}void Enablerunning(){std::cout<<"线程正在运行"<<std::endl;_isrunning = true;}static void* Routine(void*args){//static,没有默认指针,需要在线程创建的时候,通过args传回this指针Thread<T>* self = static_cast<Thread<T>*>(args);//强转成Thread<T*>类型,self->Enablerunning();if(self->_isdetach){self->Enabledetach();}self->_func(self->_data);//调用函数要加上()括号才可以调用return nullptr;}public:Thread(func_t func,T data)//传参 T data:_tid(0),_isdetach(false),_isrunning(false),_res(nullptr),_func(func),_data(data)//初始化参数{_name = "thread - " + std::to_string(number++);}void Detach(){if(_isdetach)return;if(_isrunning){pthread_detach(_tid);std::cout<<"线程分离成功"<<std::endl;Enabledetach();}}bool Start(){if(_isrunning)return false;//线程正在运行,不可再次启动int n = pthread_create(&_tid,nullptr,Routine,this);if( n != 0 ){std::cerr<<"创建线程错误"<<strerror(n)<<std::endl;return false;}else{std::cout<<"线程创建成功:"<<_name<<std::endl;return true;}}bool Stop(){if(_isrunning){int n = pthread_cancel(_tid);if(n != 0){std::cerr<<"线程停止错误:"<<strerror(n)<<std::endl;return false;}else{_isrunning = false;std::cout<<"线程停止:"<<_name<<std::endl;return true;}}}void Join(){if(_isdetach){std::cout<<"已经被分离的线程无法join"<<std::endl;return;}int n = pthread_join(_tid,&_res);if(n != 0){std::cerr<<"线程join错误:"<<strerror(n)<<std::endl;}else{std::cout << "线程join成功" << std::endl;}}~Thread(){}private:pthread_t _tid;bool _isdetach;bool _isrunning;std::string _name;void* _res;func_t _func;T _data;};
}
#endif

Main.cc

#include "Thread.hpp"
#include <unistd.h>using namespace ThreadModlue;// 我们可以传递对象吗???
class ThreadData
{
public:pthread_t tid;std::string name;
};void Count(ThreadData td)
{while (true){std::cout << "我是一个新线程" << std::endl;sleep(1);}
}int main()
{ThreadData td;Thread<ThreadData> t(Count, td);t.Start();sleep(5);t.Stop();t.Join();return 0;
}

 Makefile

test_thread:Main.ccg++ -o $@ $^ -lpthread
.PHONY:clean
clean:rm -f test_thread

结果

 线程局部存储4threadlocal

test.cc

#include <pthread.h>
#include <iostream>
#include <string>
#include <unistd.h>// 该count叫做线程的局部存储!
int count = 1;
// 线程局部存储有什么用?全局变量,我又不想让这个全局变量被其他线程看到!
// 线程局部存储,只能存储内置类型和部分指针std::string Addr(int &c)
{char addr[64];snprintf(addr, sizeof(addr), "%p", &c);return addr;
}void *routine1(void *args)
{(void)args;while (true){std::cout << "thread - 1, count = " << count << "[我来修改count], "<< "&count: " << Addr(count) << std::endl;count++;sleep(1);}
}void *routine2(void *args)
{(void)args;while (true){std::cout << "thread - 2, count = " << count<< ", &count: " << Addr(count) << std::endl;sleep(1);}
}int main()
{pthread_t tid1, tid2;pthread_create(&tid1, nullptr, routine1, nullptr);pthread_create(&tid2, nullptr, routine2, nullptr);pthread_join(tid1, nullptr);pthread_join(tid2, nullptr);return 0;
}

Makefile

test_thread:test.ccg++ -o $@ $^ -lpthread
.PHONY:clean
clean:rm -f test_thread

结果: 

全局变量被两个线程共享 ,线程1修改全局变量count,线程2也可以看得到

添加:__thread

#include <pthread.h>
#include <iostream>
#include <string>
#include <unistd.h>// 该count叫做线程的局部存储!
__thread int count = 1;
// 线程局部存储有什么用?全局变量,我又不想让这个全局变量被其他线程看到!
// 线程局部存储,只能存储内置类型和部分指针std::string Addr(int &c)
{char addr[64];snprintf(addr, sizeof(addr), "%p", &c);return addr;
}void *routine1(void *args)
{(void)args;while (true){std::cout << "thread - 1, count = " << count << "[我来修改count], "<< "&count: " << Addr(count) << std::endl;count++;sleep(1);}
}void *routine2(void *args)
{(void)args;while (true){std::cout << "thread - 2, count = " << count<< ", &count: " << Addr(count) << std::endl;sleep(1);}
}int main()
{pthread_t tid1, tid2;pthread_create(&tid1, nullptr, routine1, nullptr);pthread_create(&tid2, nullptr, routine2, nullptr);pthread_join(tid1, nullptr);pthread_join(tid2, nullptr);return 0;
}

结果:

解析:

与上面不同的是,在添加__thread后,线程1修改count,线程2读取的count不再随着线程1 的修改而修改

解释:

添加__thread修饰:该count叫做局部存储


同一个变量名:指向不同的地址
在各自的线程管理块里面创建存储 

pthread_setname_np:设置线程的名字。

pthread_getname_np:用于获取线程的名称。

#include <pthread.h>int pthread_setname_np(pthread_t thread, const char *name);参数
pthread_t thread:要设置名称的线程 ID。如果设置为 pthread_self(),则表示当前线程。
const char *name:要设置的线程名称。通常是一个简短的字符串,长度通常不超过 16 个字符(包括终止符 \0)。
返回值
成功时返回 0。
失败时返回错误码(如 EINVAL 表示无效参数,EAGAIN 表示名称过长等)。#include <pthread.h>int pthread_getname_np(pthread_t thread, char *name, size_t len);参数
pthread_t thread:要获取名称的线程 ID。如果设置为 pthread_self(),则表示当前线程。
char *name:用于存储线程名称的缓冲区。
size_t len:缓冲区的大小。
返回值
成功时返回 0。
失败时返回错误码(如 EINVAL 表示无效参数,ERANGE 表示缓冲区太小等)。

用2.thread进行修改 

#ifndef _THREAD_H_
#define _THREAD_H_
//一个头文件保护机制,防止头文件被重复包含
#include <iostream>
#include <string>
#include <pthread.h>
#include <cstdio>
#include <cstring>
#include <functional>namespace ThreadModlue{static uint32_t number = 1;class Thread{using func_t = std::function<void()>;// 添加模版的前身private:void Enabledetach(){std::cout<<"线程被分离了"<<std::endl;_isdetach = true;}void Enablerunning(){std::cout<<"线程正在运行"<<std::endl;_isrunning = true;}static void* Routine(void*args){//static,没有默认指针,需要在线程创建的时候,通过args传回this指针Thread* self = static_cast<Thread*>(args);//强转成Thread*类型self->Enablerunning();if(self->_isdetach){self->Enabledetach();}pthread_setname_np(self->_tid, self->_name.c_str());self->_func();//调用函数要加上()括号才可以调用return nullptr;}public:Thread(func_t func):_tid(0),_isdetach(false),_isrunning(false),_res(nullptr),_func(func){_name = "thread - " + std::to_string(number++);}void Detach(){if(_isdetach)return;if(_isrunning){pthread_detach(_tid);std::cout<<"线程分离成功"<<std::endl;Enabledetach();}}bool Start(){if(_isrunning)return false;//线程正在运行,不可再次启动int n = pthread_create(&_tid,nullptr,Routine,this);if( n != 0 ){std::cerr<<"创建线程错误"<<strerror(n)<<std::endl;return false;}else{std::cout<<"线程创建成功:"<<_name<<std::endl;return true;}}bool Stop(){if(_isrunning){int n = pthread_cancel(_tid);if(n != 0){std::cerr<<"线程停止错误:"<<strerror(n)<<std::endl;return false;}else{_isrunning = false;std::cout<<"线程停止:"<<_name<<std::endl;return true;}}}void Join(){if(_isdetach){std::cout<<"已经被分离的线程无法join"<<std::endl;return;}int n = pthread_join(_tid,&_res);if(n != 0){std::cerr<<"线程join错误:"<<strerror(n)<<std::endl;}else{std::cout << "线程join成功" << std::endl;}}private:pthread_t _tid;bool _isdetach;bool _isrunning;std::string _name;void* _res;func_t _func;};
}
#endif

#include "Thread.hpp"
#include <unistd.h>
#include <vector>using namespace ThreadModlue;int main(){// Thread t([](){//     while(true)//     {//         std::cout << "我是一个新线程: "<< std::endl; // 我的线程的名字是什么呀?debug//         sleep(1);//     }// });// t.Start();// t.Detach();// sleep(2);// t.Stop();// sleep(2);// t.Join();// return 0;std::vector<Thread> threads;for (int i = 0; i < 10; i++){threads.emplace_back([](){while(true){char name[128];pthread_getname_np(pthread_self(), name, sizeof(name));std::cout << "我是一个新线程: " << name << std::endl; // 我的线程的名字是什么呀?debugsleep(1);} });}for (auto &thread : threads){thread.Start();}for (auto &thread : threads){thread.Join();}
}


 同步和互斥


5.mutex代码,加锁和解锁,见一下

// 操作共享变量会有问题的售票系统代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>int ticket = 1000;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;void *route(void *arg)
{char *id = (char *)arg;while (1){pthread_mutex_lock(&lock);if (ticket > 0) // 1. 判断{usleep(1000);                               // 模拟抢票花的时间printf("%s sells ticket:%d\n", id, ticket); // 2. 抢到了票ticket--;                                   // 3. 票数--pthread_mutex_unlock(&lock);}else{pthread_mutex_unlock(&lock);break;}}return nullptr;
}int main(void)
{pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, route, (void *)"thread 1");pthread_create(&t2, NULL, route, (void *)"thread 2");pthread_create(&t3, NULL, route, (void *)"thread 3");pthread_create(&t4, NULL, route, (void *)"thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);
}

下一篇:线程互斥:

写文章-CSDN创作中心 

相关文章:

Linux:43线程封装与互斥lesson31

mmap文件映射视屏&#xff1a;待看... 目录 线程栈 代码证明&#xff1a;一个线程的数据&#xff0c;其他线程也可以访问 线程封装 简单封装,2.thread Thread.hpp Main.cc Makefile 结果&#xff1a; ​编辑 问题1&#xff1a; 问题2&#xff1a; lamba表达式 模版封…...

stm32测频率占空比最好的方案

频率检测, 方案方法很多种, 其中最快最节省资源的方法. 分享给大家. 其它的方案都试过, 问题多多. 适合单片机在工业应用中, 1MHZ以下的频率检测. 1MHZ估计也行. 但是偏差估计是变大了. 我试过很多种方案, 可以看我前面的文章. 最后发现目前这种方案最为优秀. 主要特点为不占用…...

Redis--常见数据类型List列表

目录 一、概念 二、命令 2.1 LPUSH 2.2 LPUSHX 2.3 RPUSH 2.4 RPUSHX 2.5 LRANGE 2.6 LPOP 2.7 RPOP 2.8 LINDEX 2.9 LINSERT 2.10 LLEN 2.11 阻塞版本命令 三、内部编码 一、概念 列表类型是用来存储多个有序的字符串&#xff0c;列表中的每个字符串称为元素&…...

Linux : 多线程【线程概念】

Linux &#xff1a; 多线程【线程概念】 &#xff08;一&#xff09;线程概念线程是什么用户层的线程linux中PID与LWP的关系 (二) 进程地址空间页表(三) 线程总结线程的优点线程的缺点线程异常线程用途 &#xff08;一&#xff09;线程概念 线程是什么 在一个程序里的一个执行…...

React+Springboot项目部署ESC服务器

记录一下我个人部署Linux服务器的心得 环境介绍 ESC服务器创建时默认安装LNMP&#xff0c;即Linux&#xff0c;Nginx&#xff0c;Mysql&#xff0c;Php 所以这里不讲怎么安装Nignx和Mysql 笔者使用的Linux版本为22.0.4LTS版 前端打包 运行React打包命令进行前端项目的打包…...

python-Pandas库详细教程

python-Pandas库详细教程1 定义使用方法&#xff1a; 一、导入Pandas库代码 二、DataFrame用法Pandas索引 groupby()数值计算 定义 python中特定用于数据分析、处理的模板库。 优点&#xff1a; 处理数据便捷、简单。 使用方法&#xff1a; 处理“.csv”数据&#xff1a;rea…...

力扣刷题Day 46:搜索二维矩阵 II(240)

1.题目描述 2.思路 方法1&#xff1a;分别找到搜索矩阵的右、下边界&#xff0c;然后从[0][0]位置开始遍历这部分矩阵搜索目标值。 方法2&#xff1a;学习Krahets佬的思路&#xff0c;从搜索矩阵的左下角开始遍历&#xff0c;matrix[i][j] > target时消去第i行&#xff0c…...

C++:类和对象4

一&#xff0c;日期类实现 学习建议&#xff1a; 对于计算机学习来说&#xff0c;调试十分重要&#xff0c;所以在日常学习中一定要加大代码练习&#xff0c;刷代码题和课后自己敲出课上代码例题&#xff0c;注意不要去对比正确代码或者网上找正确代码直接使用&#xff0c;一…...

【软件工程】基于机器学习的多缺陷定位

基于机器学习的多缺陷定位&#xff08;Multi-Dault Localization, MDL&#xff09;是软件工程和自动化测试领域的重要研究方向&#xff0c;旨在通过机器学习技术高效识别代码中多个潜在缺陷的位置。以下从方法、挑战、应用场景及未来方向展开分析&#xff1a; 一、核心方法 监督…...

互联网大厂Java求职面试实战:Spring Boot到微服务的技术问答解析

&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通 &#x1f601; 2. 毕业设计专栏&#xff0c;毕业季咱们不慌忙&#xff0c;几百款毕业设计等你选。 ❤️ 3. Python爬虫专栏…...

LLMs之MCP:2025年5月2日,Anthropic 宣布 Claude 重大更新:集成功能上线,研究能力大幅提升

LLMs之MCP&#xff1a;2025年5月2日&#xff0c;Anthropic 宣布 Claude 重大更新&#xff1a;集成功能上线&#xff0c;研究能力大幅提升 导读&#xff1a;2025年5月2日&#xff0c;Anthropic 宣布 Claude 推出 Integrations 集成功能和增强型高级研究功能。Integrations 基于 …...

飞蛾扑火算法matlab实现

注意&#xff1a;此代码实现的是求目标函数最大值&#xff0c;求最小值可将适应度函数乘以-1&#xff08;框架代码已实现&#xff09;。 注意&#xff1a;此代码实现的是求目标函数最大值&#xff0c;求最小值可将适应度函数乘以-1&#xff08;框架代码已实现&#xff09;。 注…...

vector--OJ1

链接: link class Solution { public:int singleNumber(vector<int>& nums) {int ret0;for(auto a : nums){ret^a;}return ret;} };链接: link class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<int>>…...

多模态大语言模型arxiv论文略读(六十八)

Image-of-Thought Prompting for Visual Reasoning Refinement in Multimodal Large Language Models ➡️ 论文标题&#xff1a;Image-of-Thought Prompting for Visual Reasoning Refinement in Multimodal Large Language Models ➡️ 论文作者&#xff1a;Qiji Zhou, Ruoc…...

【数据库知识】Mysql进阶-高可用MHA(Master High Availability)方案

mysql高可用MHA&#xff08;Master High Availability&#xff09;方案 集群部署模式下的高可用方案一、高可用架构原理1. 核心组件2. 故障切换流程 二、详细部署步骤 (3节点集群)1. 环境准备2. 节点配置&#xff08;以 node1 为例&#xff09;3. 初始化集群4. 部署MySQL Route…...

类型别名与接口的对比与选择

在 TypeScript 中&#xff0c;类型系统是非常强大且灵活的。两种最常用的类型定义方式就是 类型别名&#xff08;type&#xff09; 和 接口&#xff08;interface&#xff09;。它们看似相似&#xff0c;实际上在用法和功能上有所不同。在本文中&#xff0c;我们将深入探讨类型…...

《Effective Python》第1章 Pythonic 思维详解——始终用括号包裹单元素元组

《Effective Python》第1章 Pythonic 思维详解——始终用括号包裹单元素元组 在 Python 编程语言中&#xff0c;元组&#xff08;tuple&#xff09;是一种不可变的数据结构&#xff0c;常用于表示一组固定的值。尽管元组的语法看似简单&#xff0c;但其中却隐藏着一些微妙的陷…...

【计算机视觉】OpenCV实战项目:ETcTI_smart_parking智能停车系统深度解析

ETcTI_smart_parking智能停车系统深度解析 1. 项目概述2. 技术原理与系统架构2.1 核心算法1) 车牌识别算法2) ETC交易验证 2.2 系统架构 3. 实战部署指南3.1 环境配置3.2 硬件部署规范3.3 系统初始化 4. 常见问题与解决方案4.1 ETC交易失败4.2 车牌识别异常4.3 系统性能瓶颈 5.…...

LintCode第807题-回文数II

描述 判断一个非负整数 n 的二进制表示是否为回文数 我们保证 0 < n < 2^32 - 1 样例1 输入: n 0 输出: True 解释: 0 的二进制表示为&#xff1a;0。 样例2 输入: n 3 输出: True 解释: 3 的二进制表示为&#xff1a;11。 样例3 输入: n 4 输出: False 解释:…...

快速傅里叶变换暴力涨点!基于时频特征融合的高创新时间序列分类模型

往期精彩内容&#xff1a; 单步预测-风速预测模型代码全家桶-CSDN博客 半天入门&#xff01;锂电池剩余寿命预测&#xff08;Python&#xff09;-CSDN博客 超强预测模型&#xff1a;二次分解-组合预测-CSDN博客 VMD CEEMDAN 二次分解&#xff0c;BiLSTM-Attention预测模型…...

股指期货的保证金交易和资金门槛是多少?

股指期货和股票交易最大的区别&#xff0c;就是它不用“全款买房”&#xff0c;而是“首付买房”——只需交一笔保证金就能撬动大额资金&#xff0c;但这也说明了门槛高、风险大。下面就来拆解&#xff0c;到底要准备多少钱才能“上车”。 一、保证金交易&#xff1a;用12万撬…...

spark:map 和 flatMap 的区别(Scala)

场景设定 假设有一个包含句子的 RDD&#xff1a; scala val rdd sc.parallelize(List("Hello World", "Hi Spark")) 目标是&#xff1a;将每个句子拆分成单词。 1. 用 map 的效果 代码示例 scala val resultMap rdd.map(sentence > sentence…...

判断两台设备是否在同一局域网内的具体方法

以下是判断两台设备是否在同一局域网内的具体方法&#xff1a; 1. 检查IP地址和子网掩码 操作步骤&#xff1a; Windows系统&#xff1a; 按 Win R 键&#xff0c;输入 cmd 并回车。输入 ipconfig&#xff0c;查看 IPv4 地址 和 子网掩码&#xff08;如 192.168.1.5/255.255.2…...

cmake:test project

本文主要探讨cmake在测试和项目中的应用。 add_test add_test(NAME <name> COMMAND <command> [<arg>...] [CONFIGURATIONS <config>...] [WORKING_DIRECTORY <dir>] [COMMAND_EXPAND_LISTS])  add_test(NAME test_uni COMMAND $<TARGET_F…...

Qwen-2.5 omni

问题1 Qwen2.5-Omni的主要功能是什么&#xff1f; Qwen2.5-Omni的主要功能是处理和生成多种模态的数据&#xff0c;包括文本、图像、音频和视频。它能够同时理解和生成这些模态的信息&#xff0c;支持复杂的多模态任务&#xff0c;例如语音对话、视频理解、图像描述生成等。 …...

Problem D: 异常2

1.题目描述 检查危险品程序&#xff1a;生成货物类、机器类&#xff0c;货物类有属性name&#xff0c;机器类有检测的check方法&#xff0c;若货物名称是炸弹、毒药、刀具&#xff0c;则抛出异常提示。 代码如下&#xff1a; import java.util.Scanner; class goods{ Stri…...

AI智慧公园管理方案:用科技重塑市民的“夜游体验”

AI智慧公园管理方案&#xff1a;多场景智能巡检与安全防控 一、背景与痛点分析 夏季夜间&#xff0c;公园成为市民休闲娱乐的核心场所&#xff0c;但管理难度随之激增&#xff1a; 宠物管理失控&#xff1a;未牵绳宠物进入园区&#xff0c;随地排泄、惊扰游客&#xff0c;甚…...

AJAX原理

AJAX使用XHR 对象和服务器进行数据交互 XHR <p class"my-p"></p><script>const xhr new XMLHttpRequest()xhr.open(GET,http://hmajax.itheima.net/api/province)xhr.addEventListener(loadend,()>{// console.log(xhr.response)const data …...

内存泄露,如何判断是资源泄露还是堆栈泄露?

作为软件测试工程师,判断内存泄露类型对于定位和解决问题至关重要。以下是区分资源泄露和堆栈泄露的方法: 1. 基本概念区分 资源泄露(Resource Leak): 指非内存资源未正确释放,如文件句柄、数据库连接、网络套接字等 虽然不直接表现为Java堆内存增长,但会导致系统资源耗…...

无人甘蔗小车履带式底盘行走系统的研究

1.1 研究背景与意义 1.1.1 研究背景 甘蔗作为全球最重要的糖料作物之一&#xff0c;在农业经济领域占据着举足轻重的地位。我国是甘蔗的主要种植国家&#xff0c;尤其是广西、广东、云南等地&#xff0c;甘蔗种植面积广泛&#xff0c;是当地农业经济的重要支柱产业。甘蔗不仅…...

Redis设计与实现——单机Redis实现

RedisDB RedisDB的核心结构 键空间&#xff08;dict*dict&#xff09; 结构&#xff1a;哈希表&#xff08;字典&#xff09;&#xff0c;键为字符串对象&#xff08;SDS&#xff09;&#xff0c;值为 Redis 对象&#xff08;字符串、列表、哈希等&#xff09;。 功能&#x…...

ES C++客户端安装及使用

介绍 Elasticsearch &#xff0c; 简称 ES &#xff0c;它是个开源分布式搜索引擎&#xff0c;它的特点有&#xff1a;分布式&#xff0c;零配置&#xff0c;自动发现&#xff0c;索引自动分片&#xff0c;索引副本机制&#xff0c;restful 风格接口&#xff0c;多数据源&…...

C++学习之STL学习

在经过前面的简单的C入门语法的学习后&#xff0c;我们开始接触C最重要的组成部分之一&#xff1a;STL 目录 STL的介绍 什么是STL STL的历史 UTF-8编码原理&#xff08;了解&#xff09; UTF-8编码原理 核心编码规则 规则解析 编码步骤示例 1. 确定码点范围 2. 转换为…...

【东枫科技】使用LabVIEW进行NVIDIA CUDA GPU 开发

文章目录 工具包 CuLab - LabVIEW 的 GPU 工具包特性和功能功能亮点类似 LabVIEW 的 GPU 代码开发支持的功能数值类型和维数开发系统要求授权售价 工具包 CuLab - LabVIEW 的 GPU 工具包 CuLab 是一款非常直观易用的 LabVIEW 工具包&#xff0c;旨在加速 Nvidia GPU 上的计算密…...

LangChain对话链:打造智能多轮对话机器人

LangChain对话链:打造智能多轮对话机器人 目录 LangChain对话链:打造智能多轮对话机器人ConversationChain 是什么核心功能与特点基本用法示例内存机制自定义提示词应用场景与其他链的结合`SequentialChain` 是什么![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0…...

MIT 6.S081 2020 Lab3 page tables 个人全流程

文章目录 零、写在前面1、关于页表2、RISC-V Rv39页表机制3、虚拟地址设计4、页表项设计5、访存流程6、xv6 的页表切换7、页表遍历 一、Print a page table1.1 说明1.2 实现 二、A kernel page table per process2.1 说明2.2 初始化 / 映射相关2.3 用户内核页表的创建和回收2.4…...

spring cloud loadbalancer实现机房感知的负载均衡

1 概述 在同城多机房情景下&#xff0c;各个机房各自部署一套微服务集群&#xff0c;正常情况下微服务调用在本机房闭环。在如下某些灾难情景&#xff0c;可以尝试拉远调用以最大程度维持业务连续性&#xff0c;这些情景例如&#xff1a; A机房多个服务器宕机。应用由于BUG发…...

vs2022配置opencv

一、下载opencv 1、进入https://opencv.org/官网下载 2、打开下载的exe开始安装&#xff0c;自己新建一个文件夹opencv作为安装路径 3、安装完成得到opencv文件内容 4、开始配置环境变量 4.1、复制下图的路径 4.2、添加到系统环境变量 5、配置VS项目环境 5.1、添加包含目录 …...

Appium-OppoA92S-真机记坑

问题现象 使用Appium操作真机时候&#xff0c;需要安装AppiumSettings软件&#xff0c;但是实际操作&#xff0c;一直提示安装失败&#xff0c;安装包异常 问题分析 [待定] 网上找到方式&#xff0c;都尝试过&#xff0c;无效 问题解决 取消开发者模式&#xff0c;USB连接手…...

ENSP-OSPF综合实验

AR4中通过ospf获取的其他区域路由信息&#xff0c;并且通过路由汇总后简化路由信息 实现全网通&#xff0c;以及单向重发布&#xff0c;以及通过缺省双向访问&#xff0c; 通过stub简化过滤四类五类lsa&#xff0c;简化ospf路由信息 通过nssa简化ospf信息 区域汇总简化R4路由信…...

基于VSCode+PlatformIO环境的ESP8266的HX1838红外模块

以下是针对ESP8266开发板的红外遥控解码系统开发教程&#xff0c;基于VSCodePlatformIO环境编写 一、概述 本实验通过ESP8266开发板实现&#xff1a; 红外遥控信号解码自定义按键功能映射串口监控输出基础设备控制&#xff08;LED&#xff09; 硬件组成&#xff1a; NodeMC…...

HTML12:文本框和单选框

表单元素格式 属性说明type指定元素的类型。text、password、 checkbox、 radio、submit、reset、file、hidden、image 和button&#xff0c;默认为textname指定表单元素的名称value元素的初始值。type为radio时必须指定一个值size指定表单元素的初始宽度。当type为text 或pas…...

JVM规范之运行时数据区域

JVM运行时数据区 前言为什么要阅读jvm规范&#xff1f;阅读本篇文章可以学习到啥&#xff1f; 正文概述JVM线程私有的运行时数据区pc(program counter) RegisterJVM StackNative Method Stack JVM线程共享的运行时数据区HeapMethod AreaRun-time constant pool 总结参考链接 前…...

LVGL(lv_btnmatrix矩阵按钮)

文章目录 &#x1f527; 1. 基本概念&#x1f4cc; lv\_btnmatrix 是什么&#xff1f; &#x1f9f1; 2. 基本结构和用法✅ 创建按钮矩阵✅ 设置按钮文字 &#x1f9f0; 3. 设置按钮行为&#x1f504; 4. 响应按钮点击&#x1f3a8; 5. 自定义样式&#x1f4cc; 6. 使用技巧&am…...

AUTOSAR图解==>AUTOSAR_TR_AIDesignPatternsCatalogue

AUTOSAR 人工智能设计模式目录 AUTOSAR传感器执行器与仲裁设计模式的深入解析与图解 目录 简介传感器和执行器模式 架构概述组件结构交互流程应用场景 多请求者或提供者之间的仲裁模式 架构概述组件结构仲裁流程应用场景 总结 1. 简介 AUTOSAR&#xff08;AUTomotive Open Sy…...

英语时态--中英文对“时间”的不同理解

文章目录 中英文时间上的差异我现在正在休息一般现在时1. 经常发生的动作2. 表客观事实3. 表示现在的状态一般将来时1. will2. be going to含义1:打算在将来某时做某事含义2:某事预计要发生而且不可避免中英文时间上的差异 我现在正在休息 “我现在正在休息。”用英文怎么说…...

Linux基础开发工具一(yum/apt ,vim)

前言 Linux下&#xff0c;如何进行软件安装&#xff0c;查找&#xff0c;卸载 1.源代码安装 2. rpm安装方式&#xff0c;安装包的本质&#xff0c;就是把源代码在Linux下编译好&#xff0c;然后打包&#xff08;别人把自己编译好的软件打包给你让你去安装&#xff09; 上面…...

Java 线程池原理

Java 线程池是一种管理和复用线程的机制&#xff0c;其原理如下&#xff1a; 核心概念 线程池的初始化 &#xff1a;在创建线程池时&#xff0c;需要设置一些关键参数&#xff0c;如核心线程数&#xff08;corePoolSize&#xff09;、最大线程数&#xff08;maximumPoolSize&am…...

AJAX 使用 和 HTTP

ajax学习 promise和 awit Node.js 和 webpack 前端工程化 Git工具 AJAX异步的JS和XML&#xff1a; 使用XML对象和服务器通信 在这里插入图片描述 统一资源定位符 URL HTTP 超文本传输协议 域名 资源路径 资源目录和类型 URL 查询参数 使用&#xff1f;表示之后的参数…...

mem0跟Memgraph交互

目录 1. 安装和设置2. 配置连接3. 使用 mem0 进行交互4. 添加和查询数据5. 代码运行结果 1. 安装和设置 首先&#xff0c;确保你已经安装了 Memgraph 和 mem0 库。你可以使用 pip 来安装 mem0&#xff1a; uv pip install "mem0ai[graph]" uv pip install langchai…...