QT创建线程,QT多线程的创建和使用,QT线程池

news2024/12/23 6:39:29

一·、在Qt中创建多线程的原因和优势

1. **UI响应性:**
   - 在单线程模型中,如果需要执行长时间运行的任务(如网络请求、文件I/O、计算密集型操作等),这将会阻塞主线程,导致UI无响应。通过在单独的线程中执行这些任务,可以确保主线程保持响应性,提高用户体验。

2. **利用多核处理器:**
   - 多线程允许应用程序利用多核处理器的性能优势。通过并行执行任务,可以提高应用程序的性能和效率。

3. **任务分离:**
   - 将不同任务放在不同线程中可以更好地组织和管理代码,提高代码的可读性和维护性。

4. **避免阻塞:**
   - 在GUI应用程序中,使用多线程可以避免阻塞用户界面,保持程序的流畅性和响应性。

5. **并发性:**
   - 通过多线程可以实现并发处理,同时执行多个任务,提高系统的效率。

6. **异步操作:**
   - 多线程使得可以异步执行任务,比如在后台处理数据、下载文件等,在任务完成时通知主线程更新UI。

7. **减少资源冲突:**
   - 通过多线程可以降低资源竞争和冲突,避免因为多个任务同时访问资源而引起的问题。

总的来说,使用多线程可以提高应用程序的性能、响应性和并发处理能力,同时增强程序的可维护性和代码清晰度。在Qt中,通过提供丰富的多线程支持,开发者可以相对容易地实现多线程操作,并充分利用多核处理器的优势。

项目实现效果

二、多线程的创建方法(一)

通过创建多个继承与QThread的类来实现多线程的创建和使用。

本章内容实现三个子线程的创建和使用,分别实现(1)随机数的创建、(2)生成的随机数的快速排序、(3)生成的随机数的冒泡排序。同时将结果显示到主线程界面中。

一、新创建一个Class文件

这里选择QObject,因为QObject是QThread的基类

二、修改myThread的.h文件和.cpp文件

修改结果如下:

三、创建线程类对象

创建三个类对象,方便实现三个线程操作。

四、重写run方法

mythread.h文件如下:

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
//获取随机数的类对象******************************************
class Random : public QThread
{
    Q_OBJECT
public:
    explicit Random(QObject *parent = nullptr);
protected:
    //重写run方法
    virtual void run();
signals:
    void sendRandom(QVector<int> list);//传递随机数数据的信号
    void sendRandTime(int);//发送耗时
public slots:
    void Random_num_handler(int num_t);//处理主程序传递过来的随机数
private:
    int num;//随机数个数
};

//冒泡排序类对象********************************************
class MaoSort : public QThread
{
    Q_OBJECT
public:
    explicit MaoSort(QObject *parent = nullptr);
protected:
    //重写run方法
    virtual void run();
signals:
    void sendMaoSort(QVector<int> list);//发送排序完成的数列到主程序
    void sendMaoTime(int);//发送耗时
public slots:
    void Random_num_handler(QVector<int> list);//处理主程序传递过来的随机数
private:
    QVector<int> list;//存储传递过来的数列
};

//快速排序类对象*************************************************
class QuickSort : public QThread
{
    Q_OBJECT
public:
    explicit QuickSort(QObject *parent = nullptr);
protected:
    //重写run方法
    virtual void run();
signals:
    void sendQuickSort(QVector<int> list);//发送排序完成的数列到主程序
    void sendQuiTime(int);//发送耗时
public slots:
    void Random_num_handler(QVector<int>);//处理主程序传递过来的随机数
    void quickSort(QVector<int> &list, int low, int high);
private:
    QVector<int> list;//存储传递过来的数列
};

#endif // MYTHREAD_H

mythread.cpp文件如下:

#include "mythread.h"
#include <QVector> //容器
#include <QRandomGenerator> //随机数
#include <QDebug>
#include <QElapsedTimer>
//随机数类对象的构造函数************************************************************
Random::Random(QObject *parent)
    : QThread{parent}
{
    num = 10;//默认获取十个随机数
}
//重写run对象
void Random::run()
{
    QElapsedTimer time;//获取程序执行时间
    time.start();//计时开始
    QRandomGenerator randnum;//初始化随机数对象
    QVector<int> list;//初始化一个int类型的容器,存储生成的随机数

    for(int i = 0; i < num; i++)
    {
        list.push_back(randnum.bounded(10000));//randnum.bounded(200):生成0-200范围内的随机数,list.push_back:将生成的随机数添加到容器的末尾
    }

    int time_milsec = time.elapsed();//计时结束获取耗时
    emit sendRandom(list);//传递获取的随机数到主程序进行显示
    emit sendRandTime(time_milsec);//发送耗时
    qDebug()<<"获取"<<num<<"个随机数共耗时:"<<time_milsec<<"毫秒";
}
//修改随机数个数
void Random::Random_num_handler(int num_t)
{
    num = num_t;
}

//冒泡排序类对象的构造函数************************************************************
MaoSort::MaoSort(QObject *parent)
    : QThread{parent}
{
}
//重写run对象
void MaoSort::run()
{
    QElapsedTimer time;//获取程序执行时间
    time.start();//计时开始
    for(int i = 0; i < list.size(); i++)
    {
        for(int j = 0; j < list.size()-i-1; j++)
        {
            if(list.at(j) >= list.at(j+1))
            {
                int num = list.at(j);
                list.replace(j, list.at(j+1));
                list.replace(j+1, num);
            }
        }
    }
    int time_milsec = time.elapsed();//计时结束获取耗时
    emit sendMaoSort(list);//传递获取的随机数到主程序进行显示
    emit sendMaoTime(time_milsec);//发送耗时
    qDebug()<<"冒泡排序"<<list.size()<<"个随机数共耗时:"<<time_milsec<<"毫秒";
}
//存储未排序的数列
void MaoSort::Random_num_handler(QVector<int> list_t)
{
    list = list_t;
}


//快速排序类对象的构造函数***************************************************************
QuickSort::QuickSort(QObject *parent)
    : QThread{parent}
{

}
//重写run对象
void QuickSort::run()
{
    QElapsedTimer time;//获取程序执行时间
    time.start();//计时开始
    quickSort(list, 0, list.size()-1);//进行快排
    int time_milsec = time.elapsed();//计时结束获取耗时
    emit sendQuickSort(list);//传递获取的随机数到主程序进行显示
    emit sendQuiTime(time_milsec);//发送耗时
    qDebug()<<"冒泡排序"<<list.size()<<"个随机数共耗时:"<<time_milsec<<"毫秒";
}

void QuickSort::quickSort(QVector<int> &arr, int left, int right)
{
    if(left >= right)
        return;
    else
    {
        int i, j, base, temp;
        i = left, j = right;
        base = arr[left];  //取最左边的数为基准数
        while (i < j)
        {
            while (arr[j] >= base && i < j)
                j--;
            while (arr[i] <= base && i < j)
                i++;
            if(i < j)
            {
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        //基准数归位
        arr[left] = arr[i];
        arr[i] = base;
        quickSort(arr, left, i - 1);//递归左边
        quickSort(arr, i + 1, right);//递归右边
    }
}
//存储未排序的数列
void QuickSort::Random_num_handler(QVector<int> list_t)
{
    list = list_t;
}

五、连接信号与槽

六、项目资料

通过百度网盘分享的文件:mythread_1.rar
链接:https://pan.baidu.com/s/1vcVpocNKAU46xXhFCotN5Q 
提取码:htmm

三、多线程的创建方法(二)

直接使用QObject类,创建多个工作Working,通过将working移动到创建的QThread对象中来实现线程的创建

一、修改文件继承基类为QObject

这里以Random类为例:

二、创建工作working

创建working,这里可使用之前线程的run函数,将run函数替换即可,注意:需要修改函数权限为public权限。

此方法不同于重写run,故而可以直接在working函数中传递参数或者数据,可舍弃方法一中传递的随机数数量、随机数列等参数。

三、创建对应线程并移动任务到相应的线程中

四、连接各部分信号槽

五、书写各个working函数

六、代码

        mythread.h文件如下:

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
//获取随机数的类对象******************************************
class Random : public QObject
{
    Q_OBJECT
public:
    explicit Random(QObject *parent = nullptr);
    void working(int num);//生成随机数操作的函数
signals:
    void sendRandom(QVector<int> list);//传递随机数数据的信号
    void sendRandTime(int);//发送耗时
};

//冒泡排序类对象********************************************
class MaoSort : public QObject
{
    Q_OBJECT
public:
    explicit MaoSort(QObject *parent = nullptr);

   void working(QVector<int> list);
signals:
    void sendMaoSort(QVector<int> list);//发送排序完成的数列到主程序
    void sendMaoTime(int);//发送耗时
};

//快速排序类对象*************************************************
class QuickSort : public QObject
{
    Q_OBJECT
public:
    explicit QuickSort(QObject *parent = nullptr);

    void working(QVector<int> list);
signals:
    void sendQuickSort(QVector<int> list);//发送排序完成的数列到主程序
    void sendQuiTime(int);//发送耗时
public slots:
    void quickSort(QVector<int> &list, int low, int high);//快排函数
};

#endif // MYTHREAD_H

         mythread.cpp文件如下:

#include "mythread.h"
#include <QVector> //容器
#include <QRandomGenerator> //随机数
#include <QDebug>
#include <QElapsedTimer>
//随机数类对象的构造函数************************************************************
Random::Random(QObject *parent)
    : QObject{parent}
{
}
//重写run对象
void Random::working(int num)
{
    QElapsedTimer time;//获取程序执行时间
    time.start();//计时开始
    QRandomGenerator randnum;//初始化随机数对象
    QVector<int> list;//初始化一个int类型的容器,存储生成的随机数

    for(int i = 0; i < num; i++)
    {
        list.push_back(randnum.bounded(10000));//randnum.bounded(200):生成0-200范围内的随机数,list.push_back:将生成的随机数添加到容器的末尾
    }

    int time_milsec = time.elapsed();//计时结束获取耗时
    emit sendRandom(list);//传递获取的随机数到主程序进行显示
    emit sendRandTime(time_milsec);//发送耗时
    qDebug()<<"获取"<<num<<"个随机数共耗时:"<<time_milsec<<"毫秒";
}

//冒泡排序类对象的构造函数************************************************************
MaoSort::MaoSort(QObject *parent)
    : QObject{parent}
{
}
//重写run对象
void MaoSort::working(QVector<int> list)
{
    QElapsedTimer time;//获取程序执行时间
    time.start();//计时开始
    for(int i = 0; i < list.size(); i++)
    {
        for(int j = 0; j < list.size()-i-1; j++)
        {
            if(list.at(j) >= list.at(j+1))
            {
                int num = list.at(j);
                list.replace(j, list.at(j+1));
                list.replace(j+1, num);
            }
        }
    }
    int time_milsec = time.elapsed();//计时结束获取耗时
    emit sendMaoSort(list);//传递获取的随机数到主程序进行显示
    emit sendMaoTime(time_milsec);//发送耗时
    qDebug()<<"冒泡排序"<<list.size()<<"个随机数共耗时:"<<time_milsec<<"毫秒";
}


//快速排序类对象的构造函数***************************************************************
QuickSort::QuickSort(QObject *parent)
    : QObject{parent}
{

}
//重写run对象
void QuickSort::working(QVector<int> list)
{
    QElapsedTimer time;//获取程序执行时间
    time.start();//计时开始
    quickSort(list, 0, list.size()-1);//进行快排
    int time_milsec = time.elapsed();//计时结束获取耗时
    emit sendQuickSort(list);//传递获取的随机数到主程序进行显示
    emit sendQuiTime(time_milsec);//发送耗时
    qDebug()<<"冒泡排序"<<list.size()<<"个随机数共耗时:"<<time_milsec<<"毫秒";
}

void QuickSort::quickSort(QVector<int> &arr, int left, int right)
{
    if(left >= right)
        return;
    else
    {
        int i, j, base, temp;
        i = left, j = right;
        base = arr[left];  //取最左边的数为基准数
        while (i < j)
        {
            while (arr[j] >= base && i < j)
                j--;
            while (arr[i] <= base && i < j)
                i++;
            if(i < j)
            {
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        //基准数归位
        arr[left] = arr[i];
        arr[i] = base;
        quickSort(arr, left, i - 1);//递归左边
        quickSort(arr, i + 1, right);//递归右边
    }
}

widget.h文件如下:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "mythread.h"
#include <QThread>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
signals:
    void Random_num(int);//发送随机数个数信号
public slots:
    void Random_handler(QVector<int>);//处理随机数的槽函数
    void MaoSrot_handler(QVector<int>);//处理冒泡排序完数列的槽函数
    void QuickSrot_handler(QVector<int>);//处理快速排序完数列的槽函数
    //处理每个线程耗时的接收槽函数*********************************************************************
    void RandTime_handler(int);
    void MaoTime_handler(int);
    void QuiTime_handler(int);
private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    //创建子线程对象
    QThread* t1,*t2,*t3;
    //创建任务类对象
    Random * ran;//创建随机数任务指针
    MaoSort* mao;//创建冒泡排序任务指针
    QuickSort* qui;//创建快速排序认为五指针
};
#endif // WIDGET_H

widget.cpp文件如下:

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //1、创建子线程
    t1 = new QThread;
    t2 = new QThread;
    t3 = new QThread;
    //2、创建任务对象
    ran = new Random;//创建随机数线程对象
    mao = new MaoSort;//创建冒泡排序的线程对象
    qui = new QuickSort;//创建快速排序的线程对象
    //3、将任务对象移动到对应的子线程中去,此处分别移动到t1\t2\t3子线程中
    ran->moveToThread(t1);
    mao->moveToThread(t2);
    qui->moveToThread(t3);
    //4、连接参数传递和相应处理函数
    connect(this, &Widget::Random_num, ran, &Random::working);
    connect(ran, &Random::sendRandom, mao, &MaoSort::working);//传递随机数到冒泡排序任务
    connect(ran, &Random::sendRandom, qui, &QuickSort::working);//传递随机数到快排任务
    //5、连接线程执行结果和主线程处理函数
    connect(ran, &Random::sendRandom, this, &Widget::Random_handler);//连接随机数线程发送的随机数和当前界面随机数处理函数
    connect(mao, &MaoSort::sendMaoSort, this, &Widget::MaoSrot_handler);//连接冒泡线程发送的排序好的数列和当前线程排序好的数的处理函数
    connect(qui, &QuickSort::sendQuickSort, this, &Widget::QuickSrot_handler);//连接快速排序线程发送的数列和当前界面排序好的数列的处理函数
    //6、连接耗时传递和接收函数
    connect(ran, &Random::sendRandTime, this, &Widget::RandTime_handler);
    connect(mao, &MaoSort::sendMaoTime, this, &Widget::MaoTime_handler);
    connect(qui, &QuickSort::sendQuiTime, this, &Widget::QuiTime_handler);
}

Widget::~Widget()
{
    delete ui;
}
//点击开始,默认10个随机数开始生成和排序,启动三个线程,可输入随机数个数*****************************************************8
void Widget::on_pushButton_clicked()
{
    if(ui->lineEdit->text().isEmpty())//如果没输入则使用默认随机数100
    {
        emit Random_num(100);
        t1->start();//启动子线程获取随机数
    }
    else
    {
        emit this->Random_num(ui->lineEdit->text().toInt());//获取输入的随机数并发送到线程中
        t1->start();//启动获取随机数的子线程
    }
}
//处理获取的随机数显示到随机数框中*************************************************************
void Widget::Random_handler(QVector<int> list)
{
    for(int i =0; i < list.size(); i++)
    {
        ui->textEdit->append(QString::number(list.at(i)));//将随机数从容器中取出来放入控件中显示
    }
    //开始两个排序线程
    t2->start();//启动冒泡排序线程
    t3->start();//启动快排
}
//处理显示冒泡排序好的数列**************************************************************
void Widget::MaoSrot_handler(QVector<int> list)
{
    for(int i =0; i < list.size(); i++)
    {
        ui->textEdit_mao->append(QString::number(list.at(i)));//将冒泡排序好的数从容器中取出来放入控件中显示
    }
}
//处理显示快速排序好的数列**************************************************************
void Widget::QuickSrot_handler(QVector<int> list)
{
    for(int i =0; i < list.size(); i++)
    {
        ui->textEdit_qui->append(QString::number(list.at(i)));//将冒泡排序好的数从容器中取出来放入控件中显示
    }
}
//处理耗时显示到UI界面**********************************************************************
void Widget::RandTime_handler(int time)
{
    ui->label_random->setText("生成随机数耗时:"+QString::number(time)+"ms");
}
void Widget::MaoTime_handler(int time)
{
    ui->label_mao->setText("冒泡排序耗时:"+QString::number(time)+"ms");
}
void Widget::QuiTime_handler(int time)
{
    ui->label_qui->setText("快速排序耗时:"+QString::number(time)+"ms");
}

七、项目资料

通过百度网盘分享的文件:mythread_2.rar
链接:https://pan.baidu.com/s/1JV4uWC4iYyJu9vXkAOXoJA 
提取码:htmm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2164662.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式框架 - ZooKeeper

一、什么是微服务架构 1、单体架构 顾名思义一个软件系统只部署在一台服务器上。 ​ 在高并发场景中&#xff0c;比如电商项目&#xff0c;单台服务器往往难以支撑短时间内的大量请求&#xff0c;聪明的架构师想出了一个办法提高并发量&#xff1a;一台服务器不够就加一台&am…

Bottleneck、CSP、DP结构详细介绍

文章目录 前言一、BottleneckDarknetBottleneck 二、CSPCSP思想pp-picodet中的CSPLayer DP卷积 前言 本篇文章详细介绍了三种神经网络中常见的结构&#xff0c;bottleneck、CSP、DP&#xff0c;并附上了代码加深理解。 一、Bottleneck Bottleneck出现在ResNet50/101/152这种…

矩阵特征值怎么求?矩阵特征值计算器来帮你

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f4da;今天我们要探讨一个数学和编程领域中经常遇到的问题——矩阵特征值的计算方式&#xff0c;以及如何计算一个2x2矩阵的特征值。无论你是数学爱好者&#xff0c;还是编程高手&#xff0c;这个主题都可能对你有所…

29 C 语言中的随机数实现:rand 与 srand

目录 1 为什么需要随机数&#xff1f; 1.1 背景介绍 1.2 应用场景 2 C 语言实现随机数 2.1 rand() 函数 2.1.1 函数原型 2.1.2 功能说明 2.1.3 案例演示 2.2 srand() 函数 2.2.1 函数原型 2.2.2 功能说明 2.2.3 案例演示 2.3 指定范围的随机数 2.3.1 获…

为什么 qt 成为 c++ 界面编程的第一选择?

一、前言 为什么现在QT越来越成为界面编程的第一选择&#xff0c;笔者从事qt界面编程已经有接近8年&#xff0c;在这之前我做C界面都是基于MFC&#xff0c;也做过5年左右。当时为什么会从MFC转到QT&#xff0c;主要原因是MFC开发界面想做得好看一些十分困难&#xff0c;引用第…

hexo github部署,通过域名访问你的博客

hexo github部署&#xff0c;通过域名访问你的博客 hexo 常用命令hexo github 部署 在部署之前&#xff0c;了解一下hexo的常用命令 hexo 常用命令 hexo new "My New Post" # 新建文章 hexo n "My New Post"hexo generate # 生成静态文件 hexo ghexo serv…

【CTF】Nginx日志注入

Nginx日志注入&#xff1a; 日志包含漏洞的成因还是服务器没有进行严格的过滤 &#xff0c;导致用户可以进行任意文件读取&#xff0c;但是前提是服务器需要开启了记录日志的功能才可以利用这个漏洞。 对于Apache&#xff0c;日志存放路径&#xff1a;/var/log/apache/access.l…

【论文阅读】FedBABU:TOWARD ENHANCED REPRESENTATION FOR FEDERATED IMAGE CLASSIFICATION

算法流程&#xff1a; 训练过程中冻结客户端的头部参数&#xff0c;只训练主体参数。训练完之后再在客户端本地跑几个epoch微调一下&#xff08;文章推荐5个&#xff09;。 由于该算法与FedPer思路过于相似&#xff0c;故读完后跑了个实验。 FedPer:训练过程中只聚合主体参数。…

Redis --- redis事务和分布式事务锁

redis事务基本实现 Redis 可以通过 MULTI&#xff0c;EXEC&#xff0c;DISCARD 和 WATCH 等命令来实现事务(transaction)功能。 > MULTI OK > SET USER "Guide哥" QUEUED > GET USER QUEUED > EXEC 1) OK 2) "Guide哥"使用 MULTI命令后可以输入…

Linux应用开发实验班——JSON-RPC

目录 前言 1.是什么JSON-RPC 2.常用的JSON函数 1.创建JSON 2.根据名字获取JSON 3.获取JSON的值 4.删除JSON 3.如何进行远程调用 服务器 客户端 4.基于JSON-RPC进行硬件操作 课程链接 前言 学习的课程是百问网韦东山老师的课程&#xff0c;对更详细步骤感兴趣的同学…

LINUX网络编程:Tcp(2)

目录 1.Tcp流量控制 2.滑动窗口 2.1滑动窗口的更新 2.2滑动窗口的丢包问题 1.报文丢失的情况 2.ACK丢失的情况 3.拥塞控制 3.1慢启动 3.2拥塞窗口的增长 1.Tcp流量控制 为什会有流量控制&#xff1f; 1.在网络通信中&#xff0c;假如发送方的发送能力特别的强&#xff0…

支付宝沙箱环境 支付

一 什么是沙箱&#xff1a; 沙箱环境是支付宝开放平台为开发者提供的安全低门槛的测试环境 支付宝正式和沙箱环境的区别 &#xff1a; AI&#xff1a; 从沙箱到正式环境&#xff1a; 当应用程序开发完成后&#xff0c;需要将应用程序从沙箱环境迁移到正式环境。 这通常涉及…

opencv图像增强十四:opencv两种白平衡介绍及实现

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、白平衡介绍二、灰度世界法三、完美反射法 前言 在摄影与影像领域&#xff0c;白平衡是一个至关重要的概念。它直接影响着画面的色彩表现&#xff0c;关系到…

构建网络遇到的问题-AlexNet

1.对模型进行初始化采用的一般代码 def _initialize_weights(self):for m in self.modules(): # 遍历模型每一层if isinstance(m, nn.Conv2d): # 判定m层是否属于nn.Conv2d类型nn.init.kaiming_normal_(m.weight, modefan_out, nonlinearityrelu)if m.bias is not None:nn.in…

从自动化到智能化:AI如何推动业务流程自动化

引言&#xff1a;从自动化到智能化的必然趋势 在当今数字化时代&#xff0c;企业为了提升效率、降低成本&#xff0c;纷纷采用自动化技术来简化重复性任务。然而&#xff0c;传统自动化仅限于标准化操作&#xff0c;无法应对复杂的决策和多变的市场环境。随着人工智能&#xff…

基于springboot垃圾分类网站

基于springboot垃圾分类网站 摘 要 本论文主要论述了如何使用JAVA语言开发一个垃圾分类网站 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述垃圾分类网站的当…

Android开发拍身份证带人像框和国徽框效果

Android开发拍身份证带人像框和国徽框效果 拍身份证时往往要带上外框辅助用户拍照&#xff0c;这也是很常见的需求。 一、思路 自定义Camera和自定义拍照的界面&#xff0c;把外框画上去&#xff0c;做个遮罩 二、效果图&#xff1a; Android开发教程实战案例源码分享-拍身…

深入理解计算机系统-Bomb Lab

使用 头歌 平台 GDB 调试器 反汇编函数

动力锂电池电芯壳体市场前景:预计2030年全球市场规模将达到49.2亿美元

动力锂电池罐起着传输能量、承载电解液、保护安全等重要作用&#xff0c;是锂电池的重要组成部分。 据QYResearch调研团队最新报告“全球动力锂电池电芯壳体市场报告2024-2030”显示&#xff0c;预计2030年全球动力锂电池电芯壳体市场规模将达到49.2亿美元&#xff0c;未来几年…

分布式算法

分布式场景下的核心问题 分布式场景下困扰我们的3个核心问题&#xff08;CAP&#xff09;&#xff1a;一致性、可用性、分区容错性。 1、一致性&#xff08;Consistency&#xff09;&#xff1a;无论服务如何拆分&#xff0c;所有实例节点同一时间看到是相同的数据。 2、可用性…