【Qt线程】—— Qt线程详解

news2024/11/15 19:23:33

目录

(一)多线程的概述

(二)Qt线程的使用条件

(三)创建线程的方法

3.1 继承QTread,重写run()函数

3.1.1 为什么要重写

3.2 继承QObject

3.3 核心API介绍

3.4 关闭线程的使用方法

(四)QThread常用函数

(五)线程同步工具

5.1 互斥锁

5.2 信号量

5.2.1 为什么需要信号量?

5.3 条件变量

5.3.1 为什么需要条件变量?

(六)总结


(一)多线程的概述

  在Qt框架中,多线程编程是通过QThread类来实现的。QThread类提供了一种高级的、面向对象的方式来处理线程,它允许开发者将耗时的任务从主线程(GUI线程)中分离出来,以避免界面冻结和提高应用程序的响应性.


(二)Qt线程的使用条件

在Qt中,线程的使用通常是为了处理耗时的操作,以避免阻塞主界面(GUI)线程,从而保持应用程序的响应性。

  • 1.耗时操作:当需要执行耗时的操作,如文件读写、网络请求、复杂计算等,这些操作可能会占用大量CPU时间或等待外部资源,这时应考虑使用线程。
  • 2.保持界面响应:如果耗时操作在主线程中执行,可能会导致界面冻结或无响应.使用线程可以避免这种情况,让界面保持流畅。
  • 3.并发任务:当需要同时执行多个任务时,可以使用线程来实现并发处理,提高程序的效率。

(三)创建线程的方法

在Qt中,常用的创建线程的方法如下:

  • 方法⼀:继承QThread类,重写run()函数;
  • 方法⼆:继承QObject类,通过moveToThread(thread),交给thread执行


3.1 继承QTread,重写run()函数

3.1.1 为什么要重写

在Qt中,创建线程通常通过继承QThread类并重写其run()方法来实现。这是因为QThread类本身并不执行任何任务,它的主要作用是提供线程管理的功能,如启动、停止、暂停和恢复线程。run()方法是线程的入口点,类似于主线程中的main()函数。run()方法是QThread的虚函数,重写run()方法允许你定义线程将要执行的具体任务.

使用方法⼀创建线程的步骤:

  • 1. 自定义⼀个类,继承于QThread,并且只有⼀个线程处理函数(和主线程不是同⼀个线程),这个线 程处理函数主要就是重写⽗类中的run()函数。
  • 2. 线程处理函数里面写⼊需要执行的复杂数据处理;
  • 3. 启动线程不能直接调用run()函数,需要使用对象来调用start()函数实现线程启动;
  • 4. 线程处理函数执行结束后可以定义⼀个信号来告诉主线程;
  • 5. 最后关闭线程。

示例如下:

  • 1、首先新建Qt项目,设计UI界面如下:

  •  2、新建⼀个类,继承于QThread类;

程序如下:

/
//timethread.h


#ifndef TIMETHREAD_H
#define TIMETHREAD_H

#include <QWidget>
#include <QThread>
class TimeThread : public QThread
{
    Q_OBJECT
public:
    TimeThread();
    void run(); //线程任务函数

signals:
    void sendTime(QString Time); //声明信号函数
};

#endif // TIMETHREAD_H

//
// widget.h 
/


#ifndef WIDGET_H
#define WIDGET_H

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

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void handle();

private:
    Ui::Widget *ui;
    TimeThread t; //定义线程对象
};
#endif // WIDGET_H
///
// timethread.cpp 
//

#include "timethread.h"
#include <QTime>
#include <QDebug>

TimeThread::TimeThread()
{

}

void TimeThread::run()
{
    while(1)
    {
        QString time = QTime::currentTime().toString("hh:mm:ss");
        qDebug() << time;
        emit sendTime(time); //发送信号
        sleep(1);
    }
}
/
// widget.cpp


#include "widget.h"
#include "ui_widget.h"
#include "timethread.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(&t,&TimeThread::sendTime,this,&Widget::handle);
    t.start();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::handle()
{
    int value = ui->lcdNumber->intValue();
    value--;
    ui->lcdNumber->display(value);
}

执行效果: 



3.2 继承QObject

使用方法二创建线程的步骤:

  • 1. 自定义⼀个类,继承于QObject类;
  • 2. 创建⼀个自定义线程类的对象,不能指定父对象;
  • 3. 创建⼀个QThread类的对象,可以指定其父对象;
  • 4. 将自定义线程对象加入到QThread类的对象中使用;
  • 5. 使用start()函数启动线程。
  • 6.关闭线程。

说明: 调用start() 函数只是启动了线程,但是并没有开启线程处理函数,线程处理函数的开启需要用到信号槽机制。


3.3 核心API介绍

moveToThread(QThread* targetThread)将⼀个对象移动到指定的线程中运行
isRunning()如果线程正在运行则返回true;否则返回false。
quit()

告诉线程的事件循环以返回码0(success)退出。相当于调用 QThread::exit(0)。

如果线程没有事件循环,这个函数什么也不做。

wait(unsigned long time = ULONG_MAX

阻塞线程,直到满足以下任何⼀个条件: 与此QThread对象关联的线程已经完成执行(即当它从run()返回时)。如 果线程已经完成,这个函数将返回true。如果线程尚未启动,它还返回 true。

已经过了几毫秒。如果时间是ULONG_MAX(默认值),那么等待永远不 会超时(线程必须从run()返回)。如果等待超时,此函数将返回false。 这提供了与POSIXpthread_join()函数类似的功能。

示例如下:

  •  1、首先新建Qt项目,设计UI界面如下:

  • 2、新建⼀个类,继承于Qobject类; 

程序如下: 


// mythread.h 
///

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include <QThread>
#include <QDebug>
class mythread : public QObject
{
     Q_OBJECT
public:
     explicit mythread(QObject *parent = nullptr);
     void thread();
     void setflag(bool flag = true);
signals:
     void mysignal();
private:
     bool isStop;
};
#endif // MYTHREAD_H

// mythread.cpp
///

mythread::mythread(QObject *parent) : QObject(parent)
{
    isStop = false;
}
void mythread::thread()
{
     while (!isStop)
     {
         QThread::sleep(1);
         emit mysignal();
         qDebug() << "⼦线程号:" << QThread::currentThread();
         if(isStop) 
         {
             break;
         }
     }
 }
 void mythread::setflag(bool flag)
 {
     isStop = flag;
 }
///
// mywidgt.h
//

#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <mythread.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MyWidget; }
QT_END_NAMESPACE
class MyWidget : public QWidget
{
     Q_OBJECT
public:
     MyWidget(QWidget *parent = nullptr);
     ~MyWidget();
     mythread *testthread;
     QThread *thread;
signals:
     void startsignal();  //启动⼦线程的信号

private slots:
     void on_startPushbutton_clicked();
     void delsignals();
     void on_closePushbutton_clicked();
     void dealclose();
private:
     Ui::MyWidget *ui;
};#endif // MYWIDGET_

//mywidgt.cpp 


#include "mywidget.h"
#include "ui_mywidget.h"
#include <QThread>
MyWidget::MyWidget(QWidget *parent)
 : QWidget(parent)
 , ui(new Ui::MyWidget)
 {
     ui->setupUi(this);
     //动态分配空间,不能指定⽗对象
     testthread = new mythread();

     //创建⼦线程
     thread = new QThread(this);

     //将⾃定义的线程加⼊到⼦线程中
     testthread->moveToThread(thread);

     connect(testthread, &mythread::mysignal, this, &MyWidget::delsignals);
     qDebug() << "主线程号:" << QThread::currentThread();
     connect(this, &MyWidget::startsignal, testthread, &mythread::thread);
     connect(this, &MyWidget::destroyed, this, &MyWidget::dealclose);
}

MyWidget::~MyWidget()
{
     delete ui;
}
void MyWidget::on_startPushbutton_clicked()
{
     if(thread->isRunning() == true)
     {
         return;
     }
     //启动线程但是没有启动线程处理函数
  
    thread->start();
    //不能直接调⽤线程处理函数直接调⽤会导致线程处理函数和主线程处于同⼀线程
 
    emit startsignal();
}
void MyWidget::delsignals()
{
     static int i = 0;
     i ++;
     ui->lcdNumber->display(i);
}

void MyWidget::dealclose()
{
    /* 释放对象*/ 
    delete testthread;
    on_closePushbutton_clicked();
}

 执行效果如下:

说明:

  • 1、线程函数内部不允许操作UI图形界⾯,⼀般用数据处理;
  • 2、connect() 函数第五个参数表示的为连接的方式,且只有在多线程的时候才意义。 

 connect()函数第五个参数为Qt::ConnectionType,用于指定信号和槽的连接类型。同时影响信号的传递方式和槽函数的执行顺序。Qt::ConnectionType提供了以下五种方式:


3.4 关闭线程的使用方法

//此函数直接关闭线程不等待线程任务结束
void terminate();

//此函数等待线程任务结束之后关闭线程
void quit()


(四)QThread常用函数

QThread是Qt框架中用于处理多线程的核心类。它提供了一系列方法和信号,用于创建和管理线程。以下是一些QThread中常用的方法和信号的小结:

构造函数

  • QThread::QThread(QObject *parent = nullptr): 构造函数用于创建一个线程对象。可以指定父象。

常用方法

  • void QThread::start(QThread::Priority priority = InheritPriority): 启动线程。这个方法会创建一个新的线程,并在新线程中调用run()方法。

priority参数用于设置线程的优先级。

  • void QThread::quit(): 请求线程退出。这个方法会设置线程的退出标志,当线程的run()方法返回时,线程会自动退出。
  • void QThread::terminate(): 强制终止线程。这个方法会立即停止线程,不保证线程资源的正确释放,因此不推荐使用,除非在紧急情况下。
  • void QThread::wait(unsigned long time = ULONG_MAX): 等待线程结束。这个方法会阻塞调用它的线程,直到目标线程结束或超时。

线程控制信号

  • void QThread::started(): 当线程开始执行时发出此信号。
  • void QThread::finished(): 当线程执行完毕时发出此信号。
  • void QThread::terminated(): 当线程被强制终止时发出此信号。

线程状态

  • bool QThread::isRunning() const: 检查线程是否正在运行。
  • bool QThread::isFinished() const: 检查线程是否已经结束。
  • bool QThread::isInterruptionRequested() const: 检查是否请求了线程中断。

线程优先级

  • void QThread::setPriority(QThread::Priority priority) :设置线程的优先级。
  • QThread::Priority QThread::priority() const: 获取线程的当前优先级。


(五)线程同步工具

线程并行会导致资源竞争,线程同步工具会解决这些冲突。

实现线程互斥和同步常用的类有:

  • 互斥锁:QMutex、QMutexLocker
  • 条件变量:QWaitCondition • 信号量:QSemaphore
  • 读写锁:QReadLocker、QWriteLocker、QReadWriteLock

 

5.1 互斥锁

当多个线程访问和修改共享资源时,如果不加以适当的控制,就可能产生竞态条件、数据不一致甚至程序崩溃等问题。为了防止这些问题,Qt提供了多种同步机制,其中互斥锁(Mutex)是最基本也是最常用的同步工具之一。

互斥锁是⼀种保护和防止多个线程同时访问同⼀对象实例的方法,在Qt中,互斥锁主要是通过 QMutex类来处理。 

QMutex:

  • 特点:QMutex是Qt框架提供的互斥锁类,用于保护共享资源的访问,实现线程间的互斥操作。
  • 用途:在多线程环境下,通过互斥锁来控制对共享数据的访问,确保线程安全。
QMutex mutex;

mutex.lock();  //上锁
 
//
访问共享资源
 
//...
mutex.unlock();  //解锁
 

QMutexLocker

  • 特点:QMutexLocker是QMutex的辅助类,使⽤RAII(ResourceAcquisitionIsInitialization)方式 对互斥锁进行上锁和解锁操作。
  • 用途:简化对互斥锁的上锁和解锁操作,避免忘记解锁导致的死锁等问题。
QMutex mutex;
{
     QMutexLocker locker(&mutex);  //在作⽤域内⾃动上锁
 
    //访问共享资源
 
    //...
} //在作⽤域结束时⾃动解锁

QReadWriteLocker、QReadLocker、QWriteLocker

  • 特点: QReadWriteLock 是读写锁类,用于控制读和写的并发访问。 QReadLocker用于读操作上锁,允许多个线程同时读取共享资源。 QWriteLocker 用于写操作上锁,只允许⼀个线程写入共享资源。

  • 用途:在某些情况下,多个线程可以同时读取共享数据,但只有⼀个线程能够进行写操作。读写锁提供了更高效的并发访问方式。

QReadWriteLock rwLock;
//在读操作中使⽤读锁
 
{
     QReadLocker locker(&rwLock);  //在作⽤域内⾃动上读锁
 
    //读取共享资源
 
    //...
} //在作⽤域结束时⾃动解读锁
 
//在写操作中使⽤写锁
{
     //修改共享资源
 
     //...
     QWriteLocker locker(&rwLock);  //在作⽤域内⾃动上写锁
 
} //在作⽤域结束时⾃动解写锁
 

示例如下:

/
// myThread.h


#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
class myThread : public QThread
{
     Q_OBJECT
public:
     explicit myThread(QObject *parent = nullptr);
     void run();
private:
     static QMutex mutex;  //多个线程使⽤⼀把锁
 
    static int num;  //多个线程访问⼀个数据
 
};
#endif // MYTHREAD_H
/
// myThread.cpp 


 #include "mythread.h"
 #include <QDebug>
 QMutex myThread::mutex;
 int myThread::num = 0;
 myThread::myThread(QObject *parent) : QThread(parent)
 {
 }

 void myThread::run()
 {
     while(1)
     {
         this->mutex.lock(); //加锁
 
        qDebug() << "Current Thread: " << this << ", Value: " << this->num++;
        this->mutex.unlock(); //解锁
 
        QThread::sleep(1); //线程睡眠两秒
 
    }
 }

// mainwindow.h
///

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
     Q_OBJECT
public:
     MainWindow(QWidget *parent = nullptr);
     ~MainWindow();
private:
     Ui::MainWindow *ui;
};
 #endif // MAINWINDOW_H
//
// mainwindow.cpp 
/

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mythread.h"
MainWindow::MainWindow(QWidget *parent)
 : QMainWindow(parent)
 , ui(new Ui::MainWindow)
{
     ui->setupUi(this);
     myThread *t1 = new myThread(this);
     myThread *t2 = new myThread(this);
     t1->start();
     t2->start();
}
MainWindow::~MainWindow()
{
     delete ui;
}

 执行效果:

  • 两个线程使用⼀把锁,操作⼀个数据,数据会被两个线程依次打印:0、1、2、3、4...

 示例:在上述示例的基础上使⽤QMutexLocker锁。

//
// myThread.cpp 
/

#include "mythread.h"
#include <QDebug>

QMutex myThread::mutex;
int myThread::num = 0;

myThread::myThread(QObject *parent) : QThread(parent)
{
}
void myThread::run()
{
     while (1)
     {
          //QMutexLocker:创建的时候加锁,当QMutexLocker局部销毁的时候解锁
         {
              QMutexLocker lock(&this->mutex);
              qDebug() << "Current Thread: " << this << ", Value: " << this->num++;
              QThread::sleep(1);// 线程睡眠两秒
         }
     }
 
}

 



5.2 信号量

5.2.1 为什么需要信号量?

在多线程环境中,多个线程可能需要访问有限的共享资源。如果没有适当的同步机制,就可能出现多个线程同时访问同一资源的情况,导致数据损坏或不一致。

Qt提供了QSemaphore类来实现信号量。QSemaphore类提供了以下基本操作:

  • acquire(int n):尝试获取n个信号量。如果信号量的值小于n,则调用线程将被阻塞,直到信号量的值足够大。
  • release(int n):释放n个信号量,增加信号量的计数器。
  • available():返回当前可用的信号量数量。

QSemaphore

  • 特点:QSemaphore是Qt框架提供的计数信号量类,用于控制同时访问共享资源的线程数量。
  • 用途:限制并发线程数量,用于解决⼀些资源有限的问题
QSemaphore semaphore(2); //同时允许两个线程访问共享资源
 
//在需要访问共享资源的线程中
 
semaphore.acquire(); //尝试获取信号量,若已满则阻塞
 
//访问共享资源
 
//...
 semaphore.release(); //释放信号量
 
//在另⼀个线程中进⾏类似操作


5.3 条件变量

5.3.1 为什么需要条件变量?

在多线程环境中,线程可能需要等待某个条件成立才能继续执行。例如,一个线程可能需要等待另一个线程完成特定的任务或更新共享数据。没有条件变量,线程可能需要不断轮询检查条件是否满足,这会导致资源浪费和效率低下。条件变量提供了一种机制,允许线程在条件不满足时挂起,直到其他线程通知条件已满足。

Qt提供了QWaitCondition类来实现条件变量。QWaitCondition类提供了以下基本操作:

  • wait(QMutex *mutex):使当前线程等待条件变量。线程在调用此方法时必须持有与条件变量关联的互斥锁。线程将释放互斥锁并进入等待状态,直到其他线程调用wakeOne()或wakeAll()方法唤醒它。
  • wakeOne():唤醒一个等待条件变量的线程。被唤醒的线程将尝试重新获取互斥锁,并继续执行。
  • wakeAll():唤醒所有等待条件变量的线程。所有被唤醒的线程将尝试重新获取互斥锁,并继续执行。
     

 QWaitCondition

  • 特点:QWaitCondition是Qt框架提供的条件变量类,用于线程之间的消息通信和同步。
  • 用途:在某个条件满足时等待或唤醒线程,用于线程的同步和协调。
QMutex mutex;
QWaitCondition condition;
//在等待线程中
 
mutex.lock();
//检查条件是否满⾜,若不满⾜则等待

while (!conditionFullfilled()) 
{
 condition.wait(&mutex);  //等待条件满⾜并释放锁
}

//条件满⾜后继续执⾏
 //...

mutex.unlock();
//在改变条件的线程中
 
mutex.lock();
//改变条件
 
changeCondition();
condition.wakeAll(); //唤醒等待的线程
 
mutex.unlock();


(六)总结

多线程的概述

  • 多线程是现代操作系统和编程语言提供的一个核心特性,它允许程序同时执行多个任务,从而提高应用程序的效率和响应性。在多线程环境中,每个线程可以看作是程序中的一个独立执行路径,它们可以并发执行,共享进程资源,但同时拥有自己的调用栈和程序计数器。多线程编程的挑战在于确保线程安全,避免竞态条件、死锁和资源冲突等问题。

Qt线程的使用条件

Qt框架支持多线程编程,但使用线程时需要考虑以下条件:

  • 1. **耗时操作**:当需要执行耗时的操作,如文件读写、网络请求、复杂计算等,这些操作可能会占用大量CPU时间或等待外部资源,这时应考虑使用线程。
  • 2. **保持界面响应**:如果耗时操作在主线程中执行,可能会导致界面冻结或无响应。使用线程可以避免这种情况,让界面保持流畅。

创建线程的方法

在Qt中,创建线程通常涉及以下步骤:

  • 1. **继承QThread**重写run()方法
  • 2. “继承QObject”

 QThread常用函数

`QThread`类提供了一系列方法来管理线程的生命周期:

  • `start()`:启动线程,调用`run()`方法。
  • `quit()`:请求线程退出。
  • `terminate()`:强制终止线程。
  • `wait(unsigned long time = ULONG_MAX)`:等待线程结束。
  • `isRunning()`:检查线程是否正在运行。
  • `isFinished()`:检查线程是否已经结束。

线程同步工具

为了确保多线程程序的线程安全,Qt提供了多种同步工具:

  • **QMutex**:互斥锁,用于保护共享资源,确保在任何时刻只有一个线程可以访问。
  • **QMutexLocker**:辅助类,用于自动管理互斥锁的锁定和解锁。
  • **QSemaphore**:信号量,用于控制对一组资源的访问。
  • **QWaitCondition**:等待条件,允许线程在某些条件满足时被唤醒。
     

在设计多线程程序时,始终要考虑到线程安全和资源同步,以确保应用程序的正确性和效率。

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

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

相关文章

高压挑战:新能源汽车换电连接器的技术革新

摘要 随着汽车行业的电动化、网联化和智能化发展&#xff0c;新能源汽车连接器的使用量从传统汽车的600个左右增加到800至1000个。新能源汽车连接器在电连接和信号连接方面更为复杂&#xff0c;包括低压连接器和高压连接器。高压连接器面临严苛性能要求&#xff0c;如耐热性、…

Tomcat控制台乱码问题已解决(2024/9/7

步骤很详细&#xff0c;直接上教程 问题复现&#xff1a; 情景一 情景二 原因简述 这是由于编码不一致引起的&#xff0c;Tomcat启动后默认编码UTF-8&#xff0c;而Windows的默认编码是GBK。因此你想让其不乱码&#xff0c;只需配置conf\logging.properties的编码格式即可 解决…

探索Pyro4:Python中的远程对象通信艺术

文章目录 探索Pyro4&#xff1a;Python中的远程对象通信艺术背景&#xff1a;为何选择Pyro4&#xff1f;Pyro4是什么&#xff1f;如何安装Pyro4&#xff1f;简单的库函数使用方法场景应用示例常见Bug及解决方案总结 探索Pyro4&#xff1a;Python中的远程对象通信艺术 背景&…

git中,隐藏application.properties文件,修改不用提交了

git中&#xff0c;隐藏application.properties文件&#xff0c;修改不用提交了 A、将文件名放入 .gitignore 文件中 B、执行git命令隐藏文件 执行在ide上执行命令 a、执行隐藏命令 git rm --cached src/main/resources/application.properties b、执行提交命令 git commit -m…

【生日视频制作】劳斯莱斯库里南中控改名软件AE模板修改文字软件生成器教程特效素材【AE模板】

生日视频制作教程豪车劳斯莱斯库里南中控改名软件AE模板修改文字特效广告生成神器素材祝福玩法AE模板工程 怎么如何做的【生日视频制作】劳斯莱斯库里南中控改名软件AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤&#xff1a; 下载AE模板 安装AE软件 把A…

120张网络安全等保拓扑大全

120张网络安全等保拓扑大全已更新至星球&#x1f517;哦&#xff0c;有兴趣的领取吧。

处理List采用并行流处理时,通过ForkJoinPool来控制并行度失控的问题

在使用parallelStream进行处理list时&#xff0c;如不指定线程池&#xff0c;默认的并行度采用cpu核数进行并行&#xff0c;这里采用ForJoinPool来控制&#xff0c;但循环中使用了redis获取key时&#xff0c;出现失控。具体上代码。 RunWith(SpringRunner.class) SpringBootTe…

OpenFeign的使用(一)

OpenFeign的定义 OpenFeign是一个声明式的Web服务客户端&#xff0c;它简化了编写Web服务客户端的过程&#xff0c;使得微服务间的通信更加简单和灵活。它主要作用于帮助开发者方便地调用远程服务&#xff0c;让远程调用像本地方法调用一样简单。 事实上&#xff0c;远程调用的…

共享单车轨迹数据分析:以厦门市共享单车数据为例(一)

共享单车数据作为交通大数据的一个重要组成部分&#xff0c;在现代城市交通管理和规划中发挥着越来越重要的作用。通过对共享单车的数据进行深入分析&#xff0c;城市管理者和规划者能够获得大量有价值的洞察&#xff0c;这些洞察不仅有助于了解城市居民的日常出行模式&#xf…

入职国企3个月,还没碰过代码,很焦虑。。

国企 日常逛脉脉&#xff0c;看到名为「入职后发现提升很慢怎么办」的话题。 本以为是正儿八经的讨论帖&#xff0c;结果点开&#xff0c;还是有凡尔赛&#xff0c;不愧是人均 P8 交流地 &#x1f923;&#x1f923; 一位网友表示&#xff1a;自己入职了国企三个月&#xff0c;…

spring cloud gateway配置

1:Intellij 新建项目 spring-cloud-gateway 2:pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLoca…

正规式与有限自动机例题

答案&#xff1a;D 知识点&#xff1a; 正规式 正规集 举例 ab 字符串ab构成的集合 {ab} a|b 字符串a,b构成的集合 {a,b} a^* 由0或者多个a构成的字符串集合 {空,a,aa,aaa,aaaa} (a|b)^* 所有字符a和b构成的串的集合 {空,a,b,ab,aab,aba,aaab} a(a|b)^* 以a为…

145-Linux权限维持Rootkit后门Strace监控Alias别名Cron定时任务

参考 【权限维持】Linux&Rootkit后门&Strace监控&Alias别名&Cron定时任务_alias lsalerts(){ ls $* --colorauto;python -c "-CSDN博客 参考 FlowUs 息流 - 新一代生产力工具 权限维持-Linux-定时任务-Cron后门 利用系统的定时任务功能进行反弹Shell 1…

电脑WLan无线网连上没网络的问题解决方法

在公司的酒店&#xff0c;网络很差&#xff0c;每到周末网就很差&#xff0c;昨天网上还能上头条写文章&#xff0c;终于&#xff0c;今天浏览器都上不去了&#xff0c;咋回事呢&#xff1f; 明明手机能上网呀&#xff0c;明明电脑显示无线网已连接&#xff0c;没一点问题呀&a…

【语音告警】博灵智能语音报警灯JavaScript循环播报场景实例-语音报警灯|声光报警器|网络信号灯

功能说明 本文将以JavaScript代码为实例&#xff0c;讲解如何通过JavaScript代码调用博灵语音通知终端 A4实现声光语音告警。主要博灵语音通知终端如何实现无线循环播报或者周期播报的功能。 本代码实现HTTP接口的声光语音播报&#xff0c;并指定循环次数、播报内容。由于通知…

『功能项目』战士的A键连击【33】

我们打开上一篇32更换URP场景的项目&#xff0c; 本章要做的事情是切换为战士的连击动画&#xff0c;主要实现的是做了一个战士的动画行为&#xff0c;当按键盘A的时候播放一次右手攻击动画&#xff0c;在1秒内再次按A键播放左手攻击动画&#xff0c;再在1秒内按A键播放右手攻击…

Mysql 数据库免费使用

目录 前言 详细步骤 总结 前言 由于工作需要现在打算学习WPF开发&#xff0c;因为需要访问mysql数据&#xff0c;但是又不想在自己电脑上安装。于是就上网试着查了下&#xff0c;发现果然有提供免费数据库服务的网站。nice&#xff01;所以就打算写一篇文章详细记录一下&…

上海网站设计-网站手机端制作

随着移动互联网的迅猛发展&#xff0c;越来越多的人通过手机上网&#xff0c;这使得网站手机端的设计和制作变得尤为重要。在这种背景下&#xff0c;上海的网站设计行业迎来了新的机遇与挑战。 首先&#xff0c;网站手机端制作的必要性不容忽视。根据统计数据显示&#xff0c;手…

从零开始构建大语言模型并进行微调:全面指南

要从0开始搭建并训练一个大语言模型&#xff08;LLM&#xff09;&#xff0c;涉及到多个步骤和资源&#xff0c;包括理论理解、工具使用、数据准备、模型训练与微调。以下是一个从基础到应用的指南&#xff0c;帮助你理解并逐步实现这一目标。 1. 理解基础概念 在开始搭建大语…

Python的math库——常用数学函数全解析

文末赠免费精品编程资料~~ 一、math模块简介 math 是 Python 内置的一个标准库&#xff0c;它包含了许多执行复杂数学运算的函数&#xff0c;如三角函数、对数函数、指数函数等。 二、常用函数详解与示例 基本数学运算 math.sqrt(x): 计算平方根。 import math# 计算平方根…