【QT】系统-下

news2025/1/20 1:11:22

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣
🏠个人专栏:QT

在这里插入图片描述


目录

  • 👉🏻QThead
    • run()
  • 👉🏻QMutex
  • 👉🏻QWaitCondition
  • 👉🏻QUdpSocket
    • 常用API
  • 👉🏻QNetworkDatagram
  • 👉🏻Udp实现客户端和服务端回显

👉🏻QThead

QThread是Qt框架中用于多线程编程的基类,它提供了创建和管理线程的能力。以下是QThread的一些常用API:
在这里插入图片描述

run()

在这里插入图片描述
根据官方文档,我们需要重写run函数

  1. 创建 QThread 的子类

通常,你会通过继承 QThread 并重写其 run() 方法来创建自定义的线程类。run() 方法包含了线程将要执行的代码。

#include <QThread>

class WorkerThread : public QThread
{
    Q_OBJECT

public:
    void run() override {
        // 在这里编写线程要执行的代码
        // 例如,一个耗时的循环
        for (int i = 0; i < 5; ++i) {
            QThread::sleep(1); // 模拟耗时操作
            qDebug() << "Working in thread" << QThread::currentThreadId();
        }
    }
};
  1. 创建并启动线程

然后,你可以创建 WorkerThread 的实例,并调用其 start() 方法来启动线程。start() 方法会自动调用 run() 方法。

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    WorkerThread *worker = new WorkerThread();
    worker->start(); // 启动线程

    // 主线程可以继续执行其他任务
    qDebug() << "Working in main thread" << QThread::currentThreadId();

    // 等待线程完成
    worker->wait();

    delete worker;

    return a.exec();
}

👉🏻QMutex

QMutex 是 Qt 框架中用于管理对共享资源的互斥访问的一个类。在多线程程序中,多个线程可能会尝试同时访问同一个资源(如内存中的变量、文件句柄等),这可能导致数据损坏或不一致。QMutex 提供了一种机制来确保在同一时间内只有一个线程可以访问特定的资源。

基本使用

  1. 包含头文件

在你的 Qt 项目中,使用 QMutex 之前需要包含相应的头文件:

#include <QMutex>
  1. 创建 QMutex 实例

你可以在你的类内部或外部创建一个 QMutex 的实例。通常,这个实例会被声明为类的成员变量,以便在整个类中都能访问它。

QMutex mutex;

或者作为类的成员:

class MyClass {
public:
    MyClass() {}

    void someFunction() {
        // 使用 mutex
    }

private:
    QMutex mutex;
};
  1. 锁定和解锁
  • 锁定(Lock):在访问共享资源之前,你需要锁定 QMutex。这可以通过调用 lock() 方法实现。如果 QMutex 已经被另一个线程锁定,当前线程将被阻塞,直到 QMutex 被解锁。
mutex.lock();
// 访问共享资源
// ...
  • 解锁(Unlock):完成资源访问后,你需要通过调用 unlock() 方法来解锁 QMutex,以便其他线程可以访问该资源。
// 完成资源访问
mutex.unlock();
  1. 使用 QMutexLocker(推荐)

虽然直接调用 lock()unlock() 方法可以工作,但 Qt 推荐使用 QMutexLocker 类来自动管理锁的获取和释放。QMutexLocker 是一个在构造时自动锁定 QMutex,在析构时自动解锁 QMutex 的类。这有助于避免忘记解锁或在发生异常时未解锁的问题。

QMutex mutex;

void someFunction() {
    QMutexLocker locker(&mutex);
    // 访问共享资源
    // ...
    // 当离开此作用域时,locker 对象被销毁,自动调用 unlock()
}

注意事项

  • 避免死锁:确保在程序中不会以循环的方式锁定多个 QMutex,这可能导致死锁。
  • 锁粒度:尽量减小锁的范围,只在必要时锁定,以提高程序的并发性能。
  • 锁的性能:虽然 QMutex 提供了必要的同步机制,但过多的锁操作可能会降低程序的性能。在设计多线程程序时,要仔细考虑锁的使用。

使用 QMutex 可以帮助你在 Qt 程序中安全地管理多线程对共享资源的访问。

👉🏻QWaitCondition

QWaitCondition是Qt框架中用于线程间同步的一个重要机制,它允许线程等待某个条件的发生,并在条件满足时被唤醒。以下是QWaitCondition的基本使用方法:

  1. 基本概念
  • 条件变量:QWaitCondition本质上是一个条件变量,用于线程间的同步。
  • 互斥锁:QWaitCondition通常与QMutex一起使用,以确保在访问共享资源或条件时的线程安全。
  1. 主要函数
  • wait(QMutex* mutex, unsigned long time = ULONG_MAX):使当前线程在指定的互斥锁上等待条件的发生。如果条件未满足,线程将阻塞;如果指定了超时时间(time),则线程将在超时后继续执行。
  • wakeOne():唤醒在QWaitCondition上等待的一个线程(如果有的话)。
  • wakeAll():唤醒在QWaitCondition上等待的所有线程。
  1. 使用步骤

等待条件

  1. 锁定互斥锁:在调用wait()之前,必须首先锁定一个互斥锁,以保护共享资源和条件变量。
  2. 调用wait():调用QWaitCondition的wait()函数,传入之前锁定的互斥锁。wait()函数内部会释放互斥锁,使其他线程可以修改条件或共享资源。当条件满足时,或超时时间到达时,wait()函数将返回,并重新获取互斥锁。
  3. 检查条件:从wait()返回后,应检查条件是否真正满足,因为可能存在“虚假唤醒”(spurious wakeup)的情况。
  4. 解锁互斥锁:在继续执行之前,应解锁互斥锁。

唤醒线程

  1. 锁定互斥锁:在修改条件或共享资源之前,必须首先锁定互斥锁。

  2. 修改条件:根据需要进行操作,以改变条件的状态。

  3. 唤醒线程:使用wakeOne()或wakeAll()函数唤醒等待的线程。

  4. 解锁互斥锁:在完成操作后,应解锁互斥锁。

  5. 示例场景

场景一:单个线程等待条件

QWaitCondition condition;
QMutex mutex;
bool conditionMet = false;

// 等待条件的线程
mutex.lock();
while (!conditionMet) {
    condition.wait(&mutex); // 等待条件发生
    // 处理条件满足后的操作
}
mutex.unlock();

// 在其他线程中
mutex.lock();
conditionMet = true; // 设置条件满足
condition.wakeOne(); // 唤醒等待的线程
mutex.unlock();

场景二:多个线程等待同一个条件

QWaitCondition condition;
QMutex mutex;
int counter = 0;

// 等待条件的线程1和线程2
mutex.lock();
while (counter < 10) { // 或其他条件
    condition.wait(&mutex); // 等待条件发生
}
mutex.unlock();

// 在其他线程中
mutex.lock();
counter = 15; // 设置条件满足
condition.wakeAll(); // 唤醒所有等待的线程
mutex.unlock();
  1. 注意事项
  • 虚假唤醒:由于系统调度等原因,线程可能会被虚假唤醒。因此,在wait()返回后,应检查条件是否真正满足。
  • 超时等待:wait()函数支持超时等待,可以在条件长时间未满足时避免线程永久挂起。
  • 线程安全:QWaitCondition和QMutex的所有操作都是线程安全的,可以在多线程环境中安全使用。

通过以上介绍,可以了解到QWaitCondition在Qt多线程编程中的基本使用方法和重要性。

👉🏻QUdpSocket

QUdpSocket是Qt框架中用于UDP网络通信的一个类,它继承自QAbstractSocket,提供了发送和接收UDP数据报的功能。UDP(User Datagram Protocol,用户数据报协议)是一种轻量级、不可靠、面向数据报的无连接协议,适用于对可靠性要求不高的场合。以下是对QUdpSocket的详细介绍:

一、基本概念

  • UDP协议:UDP是一种无连接的协议,每个数据报都是独立传输的,不会建立持久的socket连接。因此,UDP通信具有较低的延迟和较高的灵活性,但数据可能会丢失、乱序或重复。
  • QUdpSocket:QUdpSocket类用于在Qt应用程序中实现UDP网络通信。通过它,可以发送和接收UDP数据报,实现单播、广播和组播等多种通信模式。

二、主要功能

  1. 数据报发送

    • QUdpSocket提供了多个重载的writeDatagram方法来发送数据报。这些方法允许你指定目标地址(IP地址)和端口号,并将数据(通常是QByteArray类型)发送到指定的UDP客户端。
    • 数据报的长度一般建议不超过512字节,因为较大的数据报可能会被网络层分片,增加传输的复杂性和错误率。
  2. 数据报接收

    • 在接收数据报之前,通常需要使用bind方法将QUdpSocket绑定到一个端口上,以便监听传入的数据报。
    • 当有数据报到达时,QUdpSocket会发出readyRead信号。你可以在相应的槽函数中使用readDatagramreceiveDatagram方法来读取数据报。
    • readDatagram方法允许你指定一个缓冲区来接收数据报,并可选地获取发送方的地址和端口信息。
  3. 多播和广播

    • QUdpSocket支持UDP多播和广播。通过调用joinMulticastGroup方法,可以将QUdpSocket加入到指定的多播组中,以便接收该组内的数据报。
    • 要进行广播,只需将目标地址设置为特殊的广播地址(如255.255.255.255),然后发送数据报即可。在同一网络范围内的所有UDP客户端都可以接收到这个广播数据报。

三、使用注意事项

  • 端口号选择:通常选择1024到65535之间的端口号进行UDP通信。1024以下的端口号通常保留给系统或特定应用程序使用。
  • 数据报大小:如前所述,建议发送的数据报大小不超过512字节。如果需要发送更大的数据量,可以考虑将数据拆分成多个较小的数据报进行发送。
  • 错误处理:在使用QUdpSocket进行UDP通信时,需要注意处理可能发生的错误情况,如网络不可达、端口已被占用等。可以通过检查QUdpSocket的状态或捕获相关的异常来进行错误处理。

四、示例代码

以下是一个简单的QUdpSocket使用示例,展示了如何发送和接收UDP数据报:

// 发送数据报
QUdpSocket udpSocket;
QByteArray datagram = "Hello, UDP!";
udpSocket.writeDatagram(datagram.data(), datagram.size(), QHostAddress::LocalHost, 12345);

// 接收数据报
udpSocket.bind(QHostAddress::LocalHost, 54321);
connect(&udpSocket, &QUdpSocket::readyRead, this, &MyClass::readPendingDatagrams);

void MyClass::readPendingDatagrams() {
    while (udpSocket.hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket.pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        udpSocket.readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        // 处理接收到的数据报...
    }
}

在这个示例中,首先创建了一个QUdpSocket对象,并使用writeDatagram方法发送了一个UDP数据报。然后,使用bind方法将QUdpSocket绑定到一个端口上,以便接收数据报。最后,通过连接readyRead信号到槽函数readPendingDatagrams来读取和处理接收到的数据报。

常用API

  1. 构造函数和析构函数

    • QUdpSocket(QObject *parent = nullptr): 构造函数,可以指定父对象。
    • ~QUdpSocket(): 析构函数,清理资源。
  2. 绑定端口

    • bool bind(const QHostAddress &address = QHostAddress::Any, quint16 port = 0, BindMode mode = DefaultForPlatform): 将QUdpSocket绑定到指定的地址和端口上,以便接收数据报。
  3. 发送数据报

    • qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port): 发送一个数据报到指定的地址和端口。
    • qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port): 发送一个QByteArray类型的数据报到指定的地址和端口。
  4. 接收数据报

    • qint64 pendingDatagramSize() const: 返回下一个待接收的数据报的大小(字节)。
    • qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr): 读取一个数据报到指定的缓冲区,并可选地获取发送方的地址和端口。
    • qint64 receiveDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr): 与readDatagram类似,但在某些平台上可能更可靠。
  5. 连接和断开

    • 注意:QUdpSocket是无连接的,因此没有像TCP那样的connectdisconnect方法来建立或断开连接。但是,你可以通过bind来监听端口,并通过writeDatagram来发送数据报。
  6. 信号

    • void readyRead(): 当有新的数据报到达时发出此信号。
    • void errorOccurred(QAbstractSocket::SocketError socketError): 当发生错误时发出此信号,提供错误类型。
  7. 状态查询

    • QAbstractSocket::SocketState state() const: 返回QUdpSocket的当前状态(如未连接、监听中等)。
    • QAbstractSocket::SocketError error() const: 返回最后发生的错误类型。
  8. 多播和广播

    • bool joinMulticastGroup(const QHostAddress &groupAddress): 将QUdpSocket加入到指定的多播组中。
    • bool leaveMulticastGroup(const QHostAddress &groupAddress): 离开之前加入的多播组。

这些API提供了QUdpSocket进行UDP网络通信所需的基本功能。需要注意的是,由于UDP是无连接的协议,因此在使用QUdpSocket时,不需要像TCP那样建立连接,而是直接发送和接收数据报。

👉🏻QNetworkDatagram

QNetworkDatagram 简介

QNetworkDatagram 是 Qt 网络模块中的一个类,用于处理 UDP 数据报。它可以在无连接的情况下发送和接收数据,非常适合实时通信和小数据量的传输。

基本用法

  1. 创建 QNetworkDatagram
    你可以通过提供数据和目标地址来创建一个 QNetworkDatagram 对象。

    QByteArray data = "Hello, UDP!";
    QHostAddress address = QHostAddress::Broadcast; // 或者指定具体地址
    quint16 port = 1234;
    
    QNetworkDatagram datagram(data, address, port);
    
  2. 发送数据报
    使用 QUdpSocket 类来发送 QNetworkDatagram

    QUdpSocket udpSocket;
    udpSocket.writeDatagram(datagram);
    
  3. 接收数据报
    设置一个 QUdpSocket 来接收数据报,并在可读事件中处理它。

    QUdpSocket udpSocket;
    udpSocket.bind(QHostAddress::Any, port); // 绑定到指定端口
    
    connect(&udpSocket, &QUdpSocket::readyRead, [&]() {
        while (udpSocket.hasPendingDatagrams()) {
            QNetworkDatagram datagram = udpSocket.receiveDatagram();
            // 处理接收到的数据
            qDebug() << "Received:" << datagram.data() << "from" << datagram.senderAddress() << ":" << datagram.senderPort();
        }
    });
    

应用场景

  1. 实时通信:例如,在线游戏、视频会议等应用程序,使用 UDP 以减少延迟。
  2. 广播和多播:可以通过设置目标地址为广播地址或多播地址,向多个客户端发送数据。
  3. 传感器数据采集:在物联网应用中,常用于从传感器收集小量数据。

总结

QNetworkDatagram 是一个非常有用的类,可以简化 UDP 数据报的处理。结合 QUdpSocket,你可以方便地实现高效的网络通信。需要注意的是,UDP 是无连接协议,因此不保证数据的可靠性或顺序。在设计应用时,应根据需求权衡使用。

👉🏻Udp实现客户端和服务端回显

代码链接:Udp实现客户端和服务端回显
实现效果:
在这里插入图片描述


如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

视频存储EasyCVR视频监控汇聚管理平台设备录像下载报错404是什么原因?

EasyCVR视频监控汇聚管理平台是一款针对大中型项目设计的跨区域网络化视频监控集中管理平台。该平台不仅具备视频资源管理、设备管理、用户管理、运维管理和安全管理等功能&#xff0c;还支持多种主流标准协议&#xff0c;如GB28181、RTSP/Onvif、RTMP、部标JT808、GA/T 1400协…

基于SpringBoot的智能排课系统设计与实现

文未可获取一份本项目的java源码和数据库参考。 &#xff08;一&#xff09;选题来源与背景 高校的每学期伊始&#xff0c;排课是教务处工作中的重中之重。安排合理无资源冲突&#xff08;教师、教室和设备等教学资源&#xff09;的课表是教务工作必须面临的问题。传统的人工…

规模化电动汽车接入配电网调度方法

规模日益增长的电动汽车和可再生能源带来的不确定性给配电网的安全运营带来了严峻挑战。为综合考虑多重不确定性、平衡运营成本与系统可靠性,首先,提出一种基于分布鲁棒联合机会约束的电动汽车-配电网充放电调度模型。该模型将节点电压、支路功率、备用需求等通过联合机会约束建…

由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(六)

概述 在 WWDC 24 中,苹果推出了数据库框架 SwiftData 2.0 版本。听说里面新增了能让数据记录“借尸还魂”的绝妙法器,到底是真是假呢? 我们在上篇博文中介绍了 History Trace 是如何稳妥的处理数据删除操作的。而在这里,我们将继续介绍 SwiftData 2.0 中另一个新特性:“墓…

Prometheus - nVisual插件让运维更轻松

Prometheus 是一个开源的服务监控系统和时间序列数据库&#xff0c;常用于对基础设施的监控&#xff0c;监控范围涵盖了硬件层、操作系统层、中间件层、应用层等运维所需的所有监控指标类型&#xff0c;同时可利用第三方可视化工具Grafana实现时序数据的展示。然而&#xff0c;…

Redis基础(数据结构和内部编码)

目录 前言 Redis的数据结构和内部编码 string结构和内部编码 string数据机构的特点 string数据结构的内部编码 list结构和内部编码 List 数据结构的特点 List 的内部编码 1. ziplist&#xff08;压缩列表&#xff09; 2. quicklist hash结构和内部编码 hash数据结构…

OpenCV特征检测(3)计算图像中每个像素处的特征值和特征向量函数cornerEigenValsAndVecs()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算图像块的特征值和特征向量用于角点检测。 对于每一个像素 p &#xff0c;函数 cornerEigenValsAndVecs 考虑一个 blockSize blockSize 的邻…

Java 在 GIS 领域的学习路线?

Java是一门广泛应用于企业级开发的编程语言&#xff0c;而GIS则是一种常用于地理信息处理和分析的技术。将Java与GIS结合起来&#xff0c;可以在企业级应用中实现更多的功能和业务需求&#xff0c;且在实际领域越来越广泛。 Java在GIS中重要的作用 1、跨平台性 Java具有跨平台…

基于C语言+SQL Server2008实现(控制台)图书管理系统

第1章 概述 1.1项目背景 随着科技的发展&#xff0c;尤其是计算机技术的迅猛发展&#xff0c;图书馆管理的问题从以往的人工管理&#xff0c;到现在的电脑化&#xff0c;系统化&#xff0c;是对图书馆管理方法的质的飞跃&#xff0c;这些技术不仅让图书馆管理变得更加方便、快…

美国联邦基金有效利率及目标利率历史数据集(1990.1-2024.9)

美联储在2024年9月18日宣布将其调50个基点&#xff0c;降至4.75%至5.00%之间的水平。这是美联储自2020年3月以来首次降息&#xff0c;也是自2023年7月将利率水平调升至历史高位后的首次下调&#xff0c;标志着货币政策由紧缩周期向宽松周期的转向。一、数据介绍 数据名称&…

web基础—dvwa靶场(八)XSS

XSS(DOM) 跨站点脚本&#xff08;XSS&#xff09;攻击是一种注入攻击&#xff0c;恶意脚本会被注入到可信的网站中。当攻击者使用 web 应用程序将恶意代码&#xff08;通常以浏览器端脚本的形式&#xff09;发送给其他最终用户时&#xff0c;就会发生 XSS 攻击。允许这些攻击成…

网络-内核是如何与用户进程交互

1、socket的直接创建 net/socket.cSYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) {...retval sock_create(family, type, protocol, &sock);... }int sock_create(int family, int type, int protocol, struct socket **res) {return __sock_create(cu…

字符串函数的使用与模拟(2)——C语言内存函数

目录 1. memcpy函数的使用与模拟 2. memmove函数的使用与模拟 3. memset函数的使用 4. memcmp函数的使用 5. memchr函数的使用 前言&#xff1a;C语言内存函数是一组用于直接操作计算机内存的内置函数。使用时要包含头文件<string.h> 1. memcpy函数的使用与模拟 函…

【MYSQL表的增删改查(进阶)】

MYSQL表的增删改查&#xff08;进阶&#xff09; 一、新增二、查询2.1 聚合查询2.1.1 聚合函数count&#xff08;&#xff09;sum&#xff08;&#xff09;AVG&#xff08;&#xff09;MAX&#xff08;&#xff09;&#xff0c;MIN&#xff08;&#xff09;GROUP_CONCAT() 2.1.…

前端学习杂乱记录

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、Html二、CSS1. BFC布局2. 定位总结3. 动画1. transform变换2. transition过渡3. keyframes 和 animation 3. 伸缩盒模型&#xff1a;flex布局 三、JS1. 逻辑中断…

nvm安装实现node多版本的切换

nvm安装实现node多版本的切换 方式一 下载安装包安装下载安装包解压安装设置 nvm 环境变量查看 nvm 是否安装完成安装 node 环境切换 node 版本列出已经安装的版本 方式二 一键脚本安装下载安装查看 nvm 是否安装完成安装 node 环境切换 node 版本列出已经安装的版本nvm相关命令…

PyTorch中的学习率预热(warmup)

PyTorch提供了学习率调度器(learning rate schedulers)&#xff0c;用于在训练过程中实现各种调整学习率的方法。实现在torch.optim.lr_scheduler.py中&#xff0c;根据epoch数调整学习率。大多数学习率调度器可以称为背对背(back-to-back)&#xff0c;也称为链式调度器&#x…

Linux入门2

文章目录 一、Linux基本命令1.1 文件的创建和查看命令1.2 文件的复制移动删除等命令1.3 查找命令1.4 文件的筛选和管道的使用1.5 echo、tail和重定向符 二、via编辑器三、权限控制3.1 root用户&#xff08;超级管理员&#xff09;3.2 用户和用户组3.3 权限信息3.4 chmod命令 一…

Streamlit:使用 Python 快速开发 Web 应用

一、简单介绍 Streamlit 是一个开源 Python 库&#xff0c;官网地址&#xff1a; https://streamlit.io/http://StreamlitStreamlit 是一个开源的 Python 框架&#xff0c;旨在为数据科学家和 后端工程师们提供只需几行代码即可创建动态数据应用的功能。 让没有任何前端基础…

C#软键盘设计字母数字按键处理相关事件函数

应用场景&#xff1a;便携式设备和检测设备等小型设备经常使用触摸屏来代替键盘鼠标的使用&#xff0c;因此在查询和输入界面的文本或者数字输入控件中使用软件盘来代替真正键盘的输入。 软键盘界面&#xff1a;软键盘界面实质上就是一个普通的窗体上面摆放了很多图片按钮&…