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

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

目录

(一)多线程的概述

(二)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_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic: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**:等待条件,允许线程在某些条件满足时被唤醒。
     

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

相关文章:

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

目录 &#xff08;一&#xff09;多线程的概述 &#xff08;二&#xff09;Qt线程的使用条件 &#xff08;三&#xff09;创建线程的方法 3.1 继承QTread&#xff0c;重写run()函数 3.1.1 为什么要重写 3.2 继承QObject 3.3 核心API介绍 3.4 关闭线程的使用方法 &…...

Golang | Leetcode Golang题解之第391题完美矩形

题目&#xff1a; 题解&#xff1a; func isRectangleCover(rectangles [][]int) bool {type point struct{ x, y int }area, minX, minY, maxX, maxY : 0, rectangles[0][0], rectangles[0][1], rectangles[0][2], rectangles[0][3]cnt : map[point]int{}for _, rect : range…...

〖open-mmlab: MMDetection〗解析文件:mmdet/models/detectors/two_stage.py

目录 MMDetection中的两阶段检测器&#xff1a;深入解析two_stage.py源码两阶段检测器概述two_stage.py的关键组件类定义和初始化构造函数Neck头配置RPN头配置RoI头配置_load_from_state_dict方法概述参数解释代码解析 特征提取方法签名文档字符串&#xff08;Docstring&#x…...

【最新华为OD机试E卷-支持在线评测】机器人活动区域(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,…...

C语言:刷题日志(1)

一.阶乘计算升级版 本题要求实现一个打印非负整数阶乘的函数。 其中n是用户传入的参数&#xff0c;其值不超过1000。如果n是非负整数&#xff0c;则该函数必须在一行中打印出n!的值&#xff0c;否则打印“Invalid input”。 首先&#xff0c;知道阶乘是所有小于及等于该数的…...

ios私钥证书(p12)导入失败,Windows OpenSSl 1.1.1 下载

ios私钥证书(p12)导入失败 如果你用的OpenSSL版本是v3那么恭喜你V3必然报这个错&#xff0c;解决办法将OpenSSL 3降低成 v1。 Windows OpenSSl 1.1.1 下载 阿里云网盘下载地址&#xff1a;OpenSSL V1...

嵌入式面试经典30问:二

1. 嵌入式系统中&#xff0c;如何选择合适的微控制器或微处理器&#xff1f; 在嵌入式系统中选择合适的微控制器&#xff08;MCU&#xff09;或微处理器&#xff08;MPU&#xff09;时&#xff0c;需要考虑多个因素以确保所选组件能够满足项目的具体需求。以下是一些关键步骤和…...

目标检测-YOLOv1

YOLOv1介绍 YOLOv1&#xff08;You Only Look Once version 1&#xff09;是一种用于目标检测的深度学习算法&#xff0c;由Joseph Redmon等人于2016年提出。它基于单个卷积神经网络&#xff0c;将目标检测任务转化为一个回归问题&#xff0c;通过在图像上划分网格并预测每个网…...

python基础语法八-异常

书接上回&#xff1a; python基础语法一-基本数据类型 python基础语法二-多维数据类型 python基础语法三-类 python基础语法四-数据可视化 python基础语法五-函数 python基础语法六-正则匹配 python基础语法七-openpyxl操作excel 1. 异常简介 (1)异常&#xff1a;遇到…...

【堆的应用--C语言版】

前面一节我们都已将堆的结构&#xff08;顺序存储&#xff09;已经实现&#xff0c;对树的相关概念以及知识做了一定的了解。其中我们在实现删除操作和插入操作的时候&#xff0c;我们还同时实现了建大堆&#xff08;小堆&#xff09;的向上&#xff08;下&#xff09;调整算法…...

【微信小程序】搭建项目步骤 + 引入Tdesign UI

目录 创建1个空文件夹&#xff0c;选择下图基础模板 开启/支持sass 创建公共style文件并引入 引入Tdesign UI: 1. 初始化&#xff1a; 2. 安装后&#xff0c;开发工具进行构建&#xff1a; 3. 修改 app.json 4. 使用 5. 自定义主题色 创建1个空文件夹&#xff0c;选择下…...

android系统源码12 修改默认桌面壁纸--SRO方式

1、aosp12修改默认桌面壁纸 代码路径 &#xff1a;frameworks\base\core\res\res\drawable-nodpi 替换成自己的图片即可&#xff0c;不过需要覆盖所有目录下的图片。 由于是静态修改&#xff0c;则需要make一下&#xff0c;重新编译。 2、方法二Overlay方式 由于上述方法有…...

Echarts可视化

echarts是一个基于javascripts的开源可视化图表库 画图步骤&#xff1a; 1.引入echarts.js文件 <script src" https://cdn.jsdelivr.net/npm/echarts5.5.1/dist/echarts.min.js"></script> 也可将文件下载到本地通过src引入。 2. 准备一个呈现图表的…...

验证linux gpu是否可用

通过torch验证 import torchprint(torch.__version__) # 查看torch当前版本号 print(torch.version.cuda) # 编译当前版本的torch使用的cuda版本号 print(torch.cuda.is_available()) # 查看当前cuda是否可用于当前版本的Torch&#xff0c;如果输出True&#xff0c;则表示可…...

JavaScript( 简介)

目录 含义 实例 js代码位置 1 外部引入js文件 2 在 HTML 中&#xff0c;JavaScript 代码必须位于 标签之间。 小结 含义 js是一门脚本语言&#xff0c;能够改变HTML内容 实例 getElementById() 是多个 JavaScript HTML 方法之一。 本例使用该方法来“查找” id"d…...

Linux中的编译器gcc/g++

目录 一、gcc与g的区别 1.gcc编译器使用 2.g编译器使用 二、gcc/g编译器编译源文件过程 1.预处理 2.编译 3.汇编 4.链接 三、静态库和动态库 1.库中的头文件作用 2.静态库 3.动态库 四、gcc编译器的一些选项命令 一、gcc与g的区别 gcc用于编译C语言代码&#xff…...

RK3568安装部署Docker容器

设置华为镜像源 sudo sed -i s/huaweicloud.com/ustc.edu.cn/g /etc/apt/sources.list更新索引 rootok3568:/home/forlinx# sudo apt-get update Hit:1 http://ports.ubuntu.com/ubuntu-ports focal InRelease Hit:2 http://ports.ubuntu.com/ubuntu-ports focal-updates InR…...

Ubuntu 常用指令和作用解析

Ubuntu 常用指令和作用解析 Ubuntu 是一种常见的 Linux 发行版&#xff0c;它利用了 Unix 的力量和开源软件的精神。掌握常用指令可以提高我们在使用 Ubuntu 时的效率。本文将介绍一些常见的指令及其用途。 目录 更新与安装软件文件与目录操作系统信息与资源监控用户与权限管…...

2024国赛数学建模C题完整论文:农作物的种植策略

农作物种植策略优化的数学建模研究&#xff08;完整论文&#xff0c;持续更新&#xff0c;大家持续关注&#xff0c;更新见文末名片 &#xff09; 摘要 在本文中&#xff0c;建立了基于整数规划、动态规划、马尔科夫决策过程、不确定性建模、多目标优化、相关性分析、蒙特卡洛…...

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

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

指针与函数(三)

三 .指向函数的指针 函数和数组一样,经系统编译后,其目标代码在内存中连续存放,其名字本身就是一个地址,是函数的入口地址。C语言中,指针可以指向变量,也可以指向函数。 指问函数的指针的定义格式为 类型名&#xff08;*指针变量名&#xff09;参数表 其中参数表为函数指针所…...

锐捷网络2025届校园招聘正式启动,【NTA6dni】!

锐捷网络2025届校园招聘正式启动&#xff0c;内推码[NTA6dni]。 原文链接点这 投递链接点这 祝大家面试顺利&#xff0c;offer多多~ 有问题大家可以评论&#xff0c;互相交流~...

共享内存喜欢沙县小吃

旭日新摊子好耶&#xff01; 系统从0开始搭建过通信方案&#xff0c;本地通信方案的代码&#xff1a;System V IPC 里面有共享内存、消息队列、信号量 共享内存 原理 两个进程有自己的内存区域划分&#xff0c;共享内存被创建出的时候是归属操作系统的&#xff0c;还是通过…...

五、Build构建配置:jar包换名、自行定义编译规则

&#xff08;1&#xff09;jar包换名&#xff1a;finalName &#xff08;2&#xff09;自行定义编译规则&#xff08;通常不用&#xff09; Maven约定的规则就是java目录下写java代码&#xff0c;resources目录下写配置文件。 遵循规则&#xff0c;Maven会帮忙做编译。 如若…...

Html、Css3动画效果

文章目录 第九章 动画9.1 transform动画9.2 transition过渡动画9.3 定义动画 第九章 动画 9.1 transform动画 transform 2D变形 translate()&#xff1a;平移函数&#xff0c;基于X、Y坐标重新定位元素的位置 scale()&#xff1a;缩放函数&#xff0c;可以使任意元素对象尺…...

【AIStarter:AI绘画、设计、对话】零基础入门:Llama 3.1 + 千问2快速部署

对于希望在本地环境中运行先进语言模型的用户来说&#xff0c;Llama 3.1和千问2是非常不错的选择。本文将详细介绍如何在本地部署这两个模型&#xff0c;让你能够快速开始使用。 前期准备 确保你的计算机具备足够的存储空间和计算能力。安装Python环境以及必要的库&#xff0…...

多机编队—(1)ubuntu 配置Fast_Planner

文章目录 前言一、Could not find package ...二、使用error: no match for ‘operator’...总结 前言 最近想要做有轨迹引导的多机器人编队&#xff0c;打算采用分布式的编队架构&#xff0c;实时的给每个机器人规划出目标位置&#xff0c;然后通过Fast_Planner生成避障路径&…...

【数学建模经验贴】国赛拿到赛题后,该如何选题?

2024“高教社杯”全国大学生数学建模竞赛即将开赛。这可能是很多同学第一次参加国赛&#xff0c;甚至是第一次参加数学建模比赛。 那么赛题的公布也就意味着比赛的开始&#xff0c;也将是我们所要面对的第一个问题——选题。在国赛来临的前夕&#xff0c;C君想和大家聊一聊容易…...

如何快速融入大学课堂

快速融入大学课堂是适应大学生活的重要一步。以下是一些实用的建议&#xff0c;帮助你快速融入大学课堂并取得良好的学习效果。 ### 1. 提前准备 - **课前预习**&#xff1a;在上课前预习课程内容&#xff0c;了解基本概念和知识点&#xff0c;这样在课堂上更容易跟上老师的讲…...

el-table行编辑

需求&#xff1a;单点行编辑并且请求接口更新数据&#xff0c;表格中某几个字段是下拉框取值的&#xff0c;剩下的是文本域&#xff1b;展示的时候 需要区分下拉框编码还是中文 故障模式这个展示的是fault_mode编码,但要显示的文字fault_mode_chn 这点需要注意 <el-tablere…...