Linux -- 从抢票逻辑理解线程互斥
目录
抢票逻辑代码:
thread.hpp
thread.cc
运行结果:
为什么票会抢为负数?
概念前言
临界资源
临界区
原子性
数据不一致
为什么数据不一致?
互斥
概念
pthread_mutex_init(初始化互斥锁)
pthread_mutex_lock(申请互斥锁)
pthread_mutex_unlock(释放互斥锁)
pthread_mutex_destory(销毁互斥锁)
全局的互斥锁
thread.cc 代码
局部的互斥锁
thread.cc 代码
抢票逻辑代码:
thread.hpp
#ifndef __THREAD_HPP__
#define __THREAD_HPP__
#include<vector>
#include<iostream>
#include<string>
#include<functional>
#include<pthread.h>
#include<unistd.h>namespace ThreadModule
{//给 函数参数为T(T为任意类型)的引用,返回值为 void 的函数 重命名为func_ttemplate<typename T>using func_t=std::function<void(T&)>;template<typename T>class Thread{public://线程的任务void Excute(){_func(_data);}public://构造函数Thread(func_t<T> func, T &data,const std::string &name="none-name"):_func(func),_data(data),_threadname(name),_stop(true){ }//如果没有static,由于 this 指针,函数的参数有2个,而pthread_create要求函数参数只能有void*//加上static,则要求函数不能访问类内的非静态成员变量,也就避免了this指针作为函数参数 static void* threadroute(void* args){//参数从void* 类型转为Thread<T> *类型,static_cast是一种相对安全的类型转换方式Thread<T> *self=static_cast<Thread<T> *>(args);//由于没有了this指针,所以需要封装Excute函数来传递 _data参数,从而执行任务self->Excute();return nullptr;}//开始执行任务bool Start(){//创建线程int n=pthread_create(&_tid,nullptr,threadroute,this);if(!n){ _stop=false;//修改状态return true;}else{return false;}}void Detach(){//有线程启动了才分离线程if(!_stop)pthread_detach(_tid);}void Join(){if(!_stop)pthread_join(_tid,nullptr);}std::string name(){return _threadname;}void Stop(){_stop=true;}//析构函数~Thread(){ }private:std::string _threadname;//线程名bool _stop;//该线程是否启动,true表示未启动,false表示已启动pthread_t _tid;T &_data;func_t<T> _func;//线程调用的函数};
}
#endif
thread.cc
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<string>
#include<vector>
using namespace std;
#include"thread.hpp"
using namespace ThreadModule;int g_tickets=10000;//共享资源,未保护
const int num=4;void route(int &tickets)
{//票没抢完就一直抢while(true){if(tickets>0)//还有票,可以继续抢{usleep(1000);//目前抢到的票printf("get tickets:%d\n",tickets);tickets--;}else//已经没票了,不能抢了,退出{break;}}
}int main()
{std::vector<Thread<int>> threads;//创建线程for(int i=0;i<num;i++){std::string name="thread-"+std::to_string(i+1);threads.emplace_back(route,g_tickets,name);}//启动线程for(auto &threads:threads){threads.Start();}//等待线程for(auto &threads:threads){threads.Join();std::cout<<"wait thread done, thread is: "<<threads.name()<<std::endl;}//return 0;
}
运行结果:
发现票数被减为了负数,且有的票被重复抢了,每次运行的结果都不一样。
为什么票会抢为负数?
概念前言
临界资源
多线程执行流共享的资源称为临界资源。
临界区
每个线程内部,访问了临界资源的代码称为临界区。
原子性
不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成。
数据不一致
在多线程或分布式系统中,由于并发操作或其他因素导致的数据状态不符合预期的情况。当多个线程或进程同时访问和修改共享资源时,如果没有适当的同步机制,可能会出现数据不一致的问题。这可能导致系统的不稳定、错误的结果或难以调试的行为。例如,上述的运行结果中出现了剩余的票数为负数的情况,而剩余的票数不应该出现负数,数据状态不符合预期,即数据不一致。
为什么数据不一致?
我们可以来模拟一下代码的整个运行过程。
在代码中,我们创建了4个线程,每个线程都要执行以下代码,函数内中一共有 3 个地方访问了临界资源,标为1、2、3:
void route(int &tickets)
{//票没抢完就一直抢while(true){//还有票,可以继续抢if(tickets>0)//1{usleep(1000);//目前剩下的票数printf("get tickets:%d\n",tickets);//2tickets--;//3}else//已经没票了,不能抢了,退出{break;}}
}
假设现在只剩一张票了,即 g_tickets = 1:
假设现在执行的是线程 1,线程 1 进行 tickets>0 的判断,这个判断过程是由 CPU 来完成的。
系统把 g_tickets 的值从内存读到 CPU 的寄存器 ebx 中,判断结果为真,线程 1 开始执行 if 的代码块,还没执行到打印操作,线程 1 被挂起并切走了,切走时线程 1 带走了寄存器的上下文数据,g_tickets 还是 1,还没有写回到内存中!
此时轮到线程 2 执行函数了,线程 2 也进行了 tickets>0 的判断,由于 g_tickets 的值依旧为 1,和线程 1 的过程一样,所以线程 2 也执行 if 的代码块, 线程 2 也还没有执行到打印操作,就被挂起并切走了。线程 3 同理。
再次轮到线程 1 时,由于已经进行过 if 判断了,线程 1 直接执行打印操作,对 tickets -- 并把 tickets 的值写回到内存中,g_tickets 的值变为 0。 这里我们需要了解到,tickets-- 看似只有一句代码,其实要分为三个过程来执行:
- 把 tickets 从内存中读到 CPU 中;
- CPU 进行 -- 操作;
- 把 tickets 的值写回内存中。
再次轮到线程 2,因为线程 2 已经进行过 if 判断了,线程 2 以为 tickets 还是1,也直接执行打印操作,把 tickets-- 并写回到内存中,但线程 2 在进行 tickets -- 操作时,读到的 tickets 已经是 0 了,-- 操作后,tickets 变为 -1,内存中的 g_tickets 的值变为 -1.
线程 3 也是同理,-- 后 tickets 变为 -2,写回到内存后,内存中的 g_tickets 的值变为 -2.
就这样 g_tickets 的值被减到了负数!
也就是说,多线程访问共享资源 g_tickets 时,由于共享资源 g_tickets 未被保护,且 -- 操作不是原子的,在执行任何一个步骤时线程都可能被切换,导致产生了计算过程的中间状态!
互斥
由于多个执行流访问全局数据的代码,所以会发生上面的问题,多个线程共享的全局数据就是临界资源,访问了全局数据的代码其实就是临界区,换句话说,保护临界区,就可以保护临界资源,就可以解决上面数据不一致的问题。
概念
任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,对临界资源起保护作用。
pthread_mutex_init(初始化互斥锁)
#include <pthread.h>int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
初始化一个互斥锁。
mutex
:指向要初始化的互斥锁对象的指针。
attr
:指向互斥锁属性对象的指针,可以为NULL
以使用默认属性。
pthread_mutex_lock(申请互斥锁)
#include <pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);
尝试获取互斥锁。如果锁已经被其他线程持有,则当前线程将被阻塞,直到锁可用。
mutex
:指向要锁定的互斥锁对象的指针。
pthread_mutex_unlock(释放互斥锁)
#include <pthread.h>int pthread_mutex_unlock(pthread_mutex_t *mutex);
释放一个互斥锁,允许其他等待的线程获取该锁。
mutex
:指向要解锁的互斥锁对象的指针。
pthread_mutex_destory(销毁互斥锁)
#include <pthread.h>int pthread_mutex_destroy(pthread_mutex_t *mutex);
销毁一个互斥锁,释放相关资源。
mutex
:指向要销毁的互斥锁对象的指针。
加锁
注意加锁应该精细,只需要在临界区加锁,非临界区不需要加锁! 加锁成功后,只有申请到互斥锁的线程才可以访问临界区,其他线程阻塞等待,直到锁释放后,其他线程成功竞争到互斥锁,才可以访问临界区!
全局的互斥锁
如果互斥锁是全局的,或者静态的,则不需要 init 和 destory。
thread.cc 代码
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<string>
#include<vector>
using namespace std;
#include"thread.hpp"
using namespace ThreadModule;int g_tickets=10000;//共享资源,未保护
const int num=4;//一把全局的锁
pthread_mutex_t gmutex=PTHREAD_MUTEX_INITIALIZER;void route(int &tickets)
{//票没抢完就一直抢while(true){pthread_mutex_lock(&gmutex);//申请锁//还有票,可以继续抢if(tickets>0)//1{usleep(1);//目前剩下的票数printf("get tickets:%d\n",tickets);//2tickets--;//3pthread_mutex_unlock(&gmutex);//释放锁}else//已经没票了,不能抢了,退出{pthread_mutex_unlock(&gmutex);//释放锁break;}}
}int main()
{std::vector<Thread<int>> threads;//创建线程for(int i=0;i<num;i++){std::string name="thread-"+std::to_string(i+1);threads.emplace_back(route,g_tickets,name);}//启动线程for(auto &threads:threads){threads.Start();}//等待线程for(auto &threads:threads){threads.Join();std::cout<<"wait thread done, thread is: "<<threads.name()<<std::endl;}//return 0;
}
不再出现抢到负数的票和抢到重复的票的情况了,且每次运行结果都一样:
局部的互斥锁
thread.cc 代码
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<string>
#include<vector>
#include<mutex>
using namespace std;
#include"thread.hpp"
using namespace ThreadModule;int g_tickets=10000;//共享资源,未保护
const int num=4;//因为锁变成局部的,为了让route可以访问互斥锁,且统计每个线程抢到了多少张票,定义一个类
class ThreadData
{
public:ThreadData(int &tickets,std::string name,pthread_mutex_t &mutex):_tickets(tickets),_name(name),_mutex(mutex),_total(0){ }~ThreadData(){ }
public:int &_tickets;//所有线程最终都会引用同一个全局变量g_ticketsstd::string _name;int _total;pthread_mutex_t &_mutex;
};void route(ThreadData *td)
{//票没抢完就一直抢while(true){pthread_mutex_lock(&td->_mutex);//申请锁//还有票,可以继续抢if(td->_tickets>0)//1{usleep(1);//目前剩下的票数printf("%s running, get tickets:%d\n",td->_name.c_str(),td->_tickets);//2td->_tickets--;//3td->_total++;pthread_mutex_unlock(&td->_mutex);//释放锁}else//已经没票了,不能抢了,退出{pthread_mutex_unlock(&td->_mutex);//释放锁break;}}
}int main()
{//一把局部的锁pthread_mutex_t mutex;pthread_mutex_init(&mutex,nullptr);//初始化互斥锁std::vector<Thread<ThreadData*>> threads;std::vector<ThreadData*> datas;//创建线程for(int i=0;i<num;i++){std::string name="thread-"+std::to_string(i+1);ThreadData* td = new ThreadData(g_tickets,name,mutex);threads.emplace_back(route,td,name);datas.emplace_back(td);}//启动线程for(auto &threads:threads){threads.Start();}//等待线程for(auto &threads:threads){threads.Join();//std::cout<<"wait thread done, thread is: "<<threads.name()<<std::endl;}for(auto data:datas){std::cout<<data->_name<<" : "<<data->_total<<std::endl;delete data;}pthread_mutex_unlock(&mutex);//return 0;
}
封装成类
LockGuard.hpp 代码
#ifndef __LOCK_GUARD_HPP__
#define __LOCK_GUARD_HPP__
#include<pthread.h>
#include<iostream>
class LockGuard
{
public:LockGuard(pthread_mutex_t *mutex):_mutex(mutex){pthread_mutex_lock(_mutex);//加锁}~LockGuard(){pthread_mutex_unlock(_mutex);//解锁}
private:pthread_mutex_t *_mutex;
};#endif
thread.cc 代码
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<string>
#include<vector>
#include<mutex>
using namespace std;
#include"thread.hpp"
#include"LockGuard.hpp"
using namespace ThreadModule;int g_tickets=10000;//共享资源,未保护
const int num=4;//因为锁变成局部的,为了让route可以访问互斥锁,且统计每个线程抢到了多少张票,定义一个类
class ThreadData
{
public:ThreadData(int &tickets,std::string name,pthread_mutex_t &mutex):_tickets(tickets),_name(name),_mutex(mutex),_total(0){ }~ThreadData(){ }
public:int &_tickets;//所有线程最终都会引用同一个全局变量g_ticketsstd::string _name;int _total;pthread_mutex_t &_mutex;
};void route(ThreadData *td)
{//票没抢完就一直抢while(true){LockGuard guard(&td->_mutex);//临时对象//还有票,可以继续抢if(td->_tickets>0)//1{usleep(1);//目前剩下的票数printf("%s running, get tickets:%d\n",td->_name.c_str(),td->_tickets);//2td->_tickets--;//3td->_total++;}else//已经没票了,不能抢了,退出{break;}}
}int main()
{//一把局部的锁pthread_mutex_t mutex;pthread_mutex_init(&mutex,nullptr);//初始化互斥锁std::vector<Thread<ThreadData*>> threads;std::vector<ThreadData*> datas;//创建线程for(int i=0;i<num;i++){std::string name="thread-"+std::to_string(i+1);ThreadData* td = new ThreadData(g_tickets,name,mutex);threads.emplace_back(route,td,name);datas.emplace_back(td);}//启动线程for(auto &threads:threads){threads.Start();}//等待线程for(auto &threads:threads){threads.Join();//std::cout<<"wait thread done, thread is: "<<threads.name()<<std::endl;}for(auto data:datas){std::cout<<data->_name<<" : "<<data->_total<<std::endl;delete data;}pthread_mutex_unlock(&mutex);//return 0;
}
相关文章:
Linux -- 从抢票逻辑理解线程互斥
目录 抢票逻辑代码: thread.hpp thread.cc 运行结果: 为什么票会抢为负数? 概念前言 临界资源 临界区 原子性 数据不一致 为什么数据不一致? 互斥 概念 pthread_mutex_init(初始化互斥锁) p…...
免费干净!付费软件的平替款!
今天给大家介绍一个非常好用的电脑录屏软件,完全没有广告界面,非常的干净简洁。 电脑录屏 无广告的录屏软件 这个软件不需要安装,打开就能看到界面直接使用了。 软件可以全屏录制,也可以自定义尺寸进行录制。 录制的声音选择也非…...
Mybatis插件better-mybatis-generator的下载与使用
1.下载 找到设置 插件 搜索better-mybatis-generator 下载并且重启IDEA 2.连接数据库 点击测试连接 连接成功如下图 3.使用插件 选择对应的表 右击选择 注意:mysql8.0驱动一定要勾上mysql_8 其他地方不要动 然后实体类 mapper xml就都生成好了 mapper里有默认增删…...
【测试】接口测试
长期更新好文,建议关注收藏! 目录 接口规范接口测试用例设计postmanRequests 复习HTTP超文本传输协议 复习cookiesession 实现方式 1.工具 如postman ,JMeter(后者功能更全) 2.代码 pythonrequests / javahttpclient【高级】 接…...
靶机系列|VULNHUB|DC-2
免责声明: 笔记只是方便各位师傅学习知识,以下代码、网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 泷羽sec官网:https://longyusec.com/ 泷羽sec B站地址:https://s…...
上手教程:使用Terraform打造弹性VPC架构
最近Akamai发布的虚拟专用云(VPC)功能提供了一种隔离的网络,让云资源可以用私密的方式进行通信。 关于Akamai VPC功能,最棒的地方在于它有着极高的灵活性。用户可以通过Cloud Manager、开发人员工具(如CLI)…...
详解VHDL如何编写Testbench
1.概述 仿真测试平台文件(Testbench)是可以用来验证所设计的硬件模型正确性的 VHDL模型,它为所测试的元件提供了激励信号,可以以波形的方式显示仿真结果或把测试结果存储到文件中。这里所说的激励信号可以直接集成在测试平台文件中,也可以从…...
Kafka为什么要放弃Zookeeper
1.Kafka简介 Apache Kafka最早是由Linkedin公司开发,后来捐献给了Apack基金会。 Kafka被官方定义为分布式流式处理平台,因为具备高吞吐、可持久化、可水平扩展等特性而被广泛使用。目前Kafka具体如下功能: 消息队列,Kafka具有系统解耦、流…...
python 渗透开发工具之SQLMapApi Server不同IP服务启动方式处理 解决方案SqlMapApiServer外网不能访问的情况
目录 说在前面 什么是 SQLMapAPI 说明 sqlmapApi能干什么 sqlmapApi 服务安装相关 kali-sqlmap存放位置 正常启动sqlmap-api server SqlMapApi-Server 解决外网不能访问情况 说在前面 什么是sqlmap 这个在前面已经说过了,如果这个不知道,就可以…...
go语言的成神之路-筑基篇-gin常用功能
第一节-gin参数绑定 目录 第一节-?gin参数绑定 ShouldBind简要概述 功能: 使用场景: 可能的错误: 实例代码 效果展示 第二节-gin文件上传 选择要上传的文件 选择要上传的文件。 效果展示? 代码部分 第三节-gin请求重定向 第…...
K8S中,pod的创建流程
kubelet创建pod流程 流程图 OCI(Open Container Initiative)是一个由docker社区发起的项目,Docker、containerd CNI(Container Network Interface)网络配置:为容器分配IP地址、配置网络接口、设置路由 C…...
Windows系统提示synsoacc.dll文件报错要怎么解决?
一、文件丢失问题:深度剖析与应对策略 文件丢失是电脑运行时常见的问题之一。它可能由多种原因引起,如硬盘故障、病毒攻击、不当的文件操作等。当Windows系统提示synsoacc.dll丢失时,通常意味着该文件对于当前正在运行的程序或系统服务至关重…...
【从0带做】基于Springboot3+Vue3的高校食堂点餐系统
大家好,我是武哥,最近给大家手撸了一个基于SpringBoot3Vue3的高校食堂点餐系统,可用于毕业设计、课程设计、练手学习,系统全部原创,如有遇到网上抄袭站长的,欢迎联系博主~ 项目演示视频和教程视频 https:…...
C语言-基因序列转换独热码(one-hot code)
1.题目要求 (语言: C)在生物信息学家处理基因序列时,经常需要将基因序列转化为独热码,在英文文献中称做 one-hot code, 直观来说就是有多少个状态就有多少比特,而且只有一个比特为1,其他全为0的一种码制。 如基因序列有四种状态&…...
git在idea中操作频繁出现让输入token或用户密码,可以使用凭证助手(使用git命令时输入的用户密码即可) use credential helper
1、打开 idea 设置,找到 git 路径 File | Settings | Version Control | Git 2、勾选 Use credential helper 即可...
《机器视觉:开启智能新时代》
《机器视觉:开启智能新时代》 一、机器视觉:工业之眼的崛起二、核心组件:构建精准视觉系统(一)光源:照亮视界的画笔(二)镜头:聚焦精准的慧眼(三)相…...
C#冒泡排序
一、冒泡排序基本原理 冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。 以一个简单的整数数…...
计算机网络习题(第1章 概论 第2章 数据通信基础)
第1章 概论 1、计算机网络 2、互联网 3、计算机网络体系结构 分层模型 OSI/RM 7层模型 TCP/IP 5层模型 协议、PDU、SDU、SAP等术语 数据封装(计算) 第2章 数据通信基础 1、数据通信系统组成 2、主要性能指标 数据传输速率 码元速率 时延 3…...
从0入门自主空中机器人-4-【PX4与Gazebo入门】
前言: 从上一篇的文章 从0入门自主空中机器人-3-【环境与常用软件安装】 | MGodmonkeyの世界 中我们的机载电脑已经安装了系统和常用的软件,这一篇文章中我们入门一下无人机常用的开源飞控PX4,以及ROS中无人机的仿真 1. PX4的安装 1.1 PX4固件代码的下载…...
百度热力图数据日期如何选择
目录 1、看日历2、看天气 根据研究内容定,一般如果研究城市活力的话,通常会写“非重大节假日,非重大活动,非极端天气等”。南方晴天不多,有小雨或者中雨都可认为没有影响,要不然在南方很难找到完全一周没有…...
深入理解 ElasticSearch 索引与检索原理
在当今数字化浪潮中,数据呈爆炸式增长,如何高效地从海量信息里找到所需内容成为关键。ElasticSearch 凭借其卓越的索引和检索能力脱颖而出,成为众多企业与开发者的得力工具。接下来,让我们深入剖析它的索引和检索工作原理。 一、…...
汽车CAN通信逻辑与LabVIEW开发
CAN通信的核心概念 CAN(Controller Area Network)是一种多主通信协议,广泛应用于汽车电子系统中,用于控制单元之间的高效通信。 消息优先级:每个CAN帧包含唯一的标识符(ID),ID的…...
OWASP~SQL注入
文章只做学习知识,禁止违法。 一、简介 SQL注入是一种Web应用代码中的漏洞。在工作中渗透测试工作时,使用工具扫描、手工注入和绕过WAF注入等找注入点,其中一层不变的构造特殊请求,使其与数据库SQL语句进行闭合。测试完成闭合时会…...
大数据-261 实时数仓 - 业务数据库表结构 交易订单、订单产品、产品分类、商家店铺、地域组织表
点一下关注吧!!!非常感谢!!持续更新!!! Java篇开始了! MyBatis 更新完毕目前开始更新 Spring,一起深入浅出! 目前已经更新到了: H…...
大厂开发规范-如何规范的提交Git
多人协作开发提交代码通常是遵循约定式提交规范,如果严格安照约定式提交规范, 手动进行代码提交的话,那么是一件非常痛苦的事情,但是 Git 提交规范的处理又势在必行,那么怎么办呢? 经过了很多人的冥思苦想…...
深度学习中batch_size
Batch size调整和epoch/iteration的关系 训练数据集总共有1000个样本。若batch_size10,那么训练完全体样本集需要100次迭代,1次epoch。 训练样本10000条,batchsize设置为20,将所有的训练样本在同一个模型中训练5遍,则…...
SpringBoot的pom.xml文件中,scope标签有几种配置?
1.compile(默认) 含义:表示该依赖在项目的所有阶段(编译、测试、运行)都需要。 当你依赖一个库,并且这个库是你项目的核心部分,比如 Spring Boot 的spring - boot - starter - web,…...
科技快讯 | 水滴筹成为民政部指定个人求助网络服务平台;小米超级小爱首次向正式版用户开放;腾讯发布全球首个重症医疗大模型
本地 AI 开发利器,初探微软 Win11 AI Dev Gallery 功能 12月27日,科技媒体Windows Latest报道,微软推出AI Dev Gallery功能,助力开发者集成端侧AI。该功能支持Windows 10/11,提供25个示例模型,涵盖多领域。…...
在 Windows 上,如果忘记了 MySQL 密码 重置密码
在 Windows 上,如果忘记了 MySQL 密码,可以通过以下方法重置密码: 方法 1:以跳过权限验证模式启动 MySQL 并重置密码 停止 MySQL 服务: 打开 命令提示符 或 PowerShell,输入以下命令停止 MySQL 服务&#…...
Linux下载RabbitMQ,并解决Github拒绝访问443的问题
RabbitMQ Linux下载资源时,GitHub网站 443 拒绝访问 例如无法直接使用下面命令 rpm --import https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc在Linux中无法访问Github(外网)资源的都可以采用以下类似的方式 首…...
攻防世界web新手第五题supersqli
这是题目,题目看起来像是sql注入的题,先试一下最常规的,输入1,回显正常 输入1‘,显示错误 尝试加上注释符号#或者–或者%23(注释掉后面语句,使1后面的单引号与前面的单引号成功匹配就不会报错…...
什么是ondelete cascade以及使用sqlite演示ondelete cascade使用案例
什么是ondelete cascade ON DELETE CASCADE是数据库中的一种约束,用于自动删除相关的记录。具体来说,当一个表中的记录(父表)被删除时,与其相关的其他表(子表)中的记录也会被自动删除&…...
Wordperss漏洞 DeDeCMS漏洞
Wordperss漏洞 环境搭建 #执⾏命令 cd /vulhub/wordpress/pwnscriptum docker-compose up -d #靶场地址 http://8.155.7.173:8080/wp-admin/ 注册账号 登录 漏洞一:后台修改模板拿WebShell 步骤一:思路是修改其WP的模板写入⼀句话木马后门并访问其文件…...
人才公寓系统|Java|SSM|JSP|
【技术栈】 1⃣️:架构: B/S、MVC 2⃣️:系统环境:Windowsh/Mac 3⃣️:开发环境:IDEA、JDK1.8、Maven、Mysql5.7 4⃣️:技术栈:Java、Mysql、SSM、Mybatis-Plus、JSP、jquery,html 5⃣️数据库可…...
SQLite本地数据库的简介和适用场景——集成SpringBoot的图文说明
前言:现在项目普遍使用的数据库都是MySQL,而有些项目实际上使用SQLite既足矣。在一些特定的项目中,要比MySQL更适用。 这一篇文章简单的介绍一下SQLite,对比MySQL的优缺点、以及适用的项目类型和集成SpringBoot。 1. SQLite 简介 …...
sqlserver镜像设置
本案例是双机热备,只设置主体服务器(主)和镜像服务器(从),不设置见证服务器 设置镜像前先检查是否启用了 主从服务器数据库的 TCP/IP协议 和 RemoteDAC (1)打开SQL Server配置管理器…...
Chapter 03 复合数据类型-1
1.列表 Python内置的一种有序、可变的序列数据类型; 列表的定义: [ ]括起来的逗号分隔的多个元素组成的序列 列表对象的创建: (1)直接赋值 >>> list1 []#创建一个空列表赋值给list1 >>> list…...
goview——vue3+vite——数据大屏配置系统
低代码数据大屏配置系统: 数据来源是可以动态api配置的: 配置上面的api接口后,在数据过滤中进行数据格式的转化。 以上内容,来源于https://gitee.com/dromara/go-view/tree/master-fetch/ 后端代码如下,需要更改…...
Linux Shell : Process Substitution
注:本文为 “Process Substitution” 相关文章合辑。 英文引文机翻,未校。 Process Substitution. 进程替换允许使用文件名引用进程的输入或输出。它采取以下形式 <(list)or >(list)进程 list 异步运行,其输入或输出显示为文件名。…...
html转PDF
项目场景: 提示:这里简述项目相关背景: 在项目中会有一些需要页面转成PDF的情况,这里需要配合一些插件可以完成 使用html2canvas将使用canvas将页面转为base64图片流,并插入jspdf插件中,保存并下载pdf。…...
React 之 Redux =》 理解+应用
文章目录 Redux基础介绍一、概述二、元素组成1. Action(动作)2. Reducer(纯函数)3. Store(仓库) 三、原理结构四、场景应用1. 大型复杂的单页应用(SPA)2. 多用户协作的应用3. 数据持…...
生成excel文件(有备注和表头的情况)
要使用 Java 导出 Excel 文件,并且通过 ExcelProperty 注解进行列的映射,可以利用 EasyExcel 库。EasyExcel 是阿里巴巴开源的一款高性能 Excel 读写工具,它支持通过注解将类与 Excel 的列进行映射,简化了 Excel 操作的复杂性。 …...
Docker 安装全攻略:从入门到上手
Docker 安装全攻略:从入门到上手 在当今的软件开发与部署领域,Docker 已经成为了一项不可或缺的关键技术。它能够将应用程序及其依赖项打包成轻量级、可移植的容器,极大地简化了开发、测试和部署的流程。本文将详细讲解在不同操作系统下 Doc…...
@Scheduled注解的使用-SpringBoot-Springtask
Scheduled 注解是 Spring 框架中用于定时任务调度的核心注解之一。通过 Scheduled 注解,开发者可以非常方便地在 Spring 应用程序中定义和配置各种定时任务,包括固定速率执行、固定延迟执行、cron 表达式执行等。本文将详细讲解 Scheduled 注解的各个方面…...
Elasticsearch:使用 Ollama 和 Go 开发 RAG 应用程序
作者:来自 Elastic Gustavo Llermaly 使用 Ollama 通过 Go 创建 RAG 应用程序来利用本地模型。 关于各种开放模型,有很多话要说。其中一些被称为 Mixtral 系列,各种规模都有,而一种可能不太为人所知的是 openbiollm,这…...
Linux 下 Mamba 环境安装踩坑问题汇总(重置版)
导航 安装教程导航 Mamba 及 Vim 安装问题参看本人博客:Mamba 环境安装踩坑问题汇总及解决方法(初版)Linux 下Mamba 及 Vim 安装问题参看本人博客:Mamba 环境安装踩坑问题汇总及解决方法(重置版)Windows …...
(免费送源码)计算机毕业设计原创定制:Java+springboot+MySQL springboot 线上线下一体化的宠物交易
摘 要 网络发布信息有其突出的优点,即信息量大,资源丰富,更新速度快等,很符合人们希望以捷、便利的方式获得最多最有效信息的要求。本系统就是一个线上线下一体化的宠物交易,为商家提供一个信息发布的平台࿰…...
【Rust自学】7.4. use关键字 Pt.2 :重导入与换国内镜像源教程
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 7.4.1. 使用pub use重新导入名称 使用use将路径导入作用域内后。该名称在词作用域内是私有的。 以上一篇文章的代码为例: m…...
自动生成关于软件程序开发的100个文件并可提供下载入口
创建一个包含100个关于软件程序开发的文件并提供下载入口是一个庞大的任务,因为这需要编写大量的代码、文档和示例。不过,我可以提供一个大致的框架和指导,帮助你生成这些文件,并说明如何设置下载入口。 文件生成思路 编程语言文…...
Linux下基本指令
一、什么是指令 指令本质是可执行程序,在执行指令前,先在系统中查找对应的指令。在Linux系统中指令存在于/usr/bin/路径下 二、ls 指令 1、语法 ls [选项][目录或文件] 2、功能 对于目录,该命令列出该目录下的所有子目录与文件。 对于文…...