C++与Qt深度融合:高效设计多线程应用框架

news2024/7/4 5:27:19

C++与Qt深度融合:高效设计多线程应用框架

  • 1. C++与Qt线程的混合使用
    • 1.1 C++线程与Qt线程的基本概念
    • 1.2 线程间的相互依赖关系
    • 1.3 设计合理的代码框架
  • 二、深入理解C++和Qt线程模型
    • 2.1 C++线程模型
    • 2.2 Qt线程模型
    • 2.3 C++和Qt线程模型的比较
  • 三、C++和Qt线程间的互操作性
    • 3.1 std::thread与QThread的相互依赖
    • 3.2 在std::thread中使用QTimer的问题(Issues with Using QTimer in std::thread)
    • 3.3 解决方案和替代选项(Solutions and Alternatives)
  • 四、设计高效的多线程应用框架
    • 4.1 理解上下级关系
    • 4.2 设计合理的代码框架
    • 4.3 实例分析:从底层原理到上层应用
    • 4.4 架构设计实战展示

1. C++与Qt线程的混合使用

1.1 C++线程与Qt线程的基本概念

在深入讨论如何在项目中混合使用C++线程(std::thread)和Qt线程(QThread)之前,我们首先需要理解这两种线程的基本概念和特性。线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程中可以并发多个线程,每个线程并行执行不同的任务。
C++11开始,C++标准库中包含了线程库,包括线程、原子操作、互斥、条件变量和future等内建支持。其中std::thread是C++标准库中的线程类,用于管理单独的线程。std::thread使得程序能在数个处理器核心同时执行。C++20中,还引入了jthread类,它是std::thread的扩展,增加了自动合并和取消支持。
Qt线程库提供了QThread类,它允许创建和管理线程。QThread类提供了一种方式来允许多线程在程序中,这样可以在多个任务之间分配CPU时间,或者在需要执行阻塞操作时,防止程序界面冻结。QThread类提供了一种非常直观的方式来创建和管理线程,因为它允许你将线程看作是一个对象。
在理解了C++线程和Qt线程的基本概念和特性之后,我们可以开始探讨如何在项目中混合使用这两种线程。在混合使用时,我们需要考虑到线程的相互依赖关系,以及如何设计合理的代码框架来处理这种依赖关系。

1.2 线程间的相互依赖关系

在Qt中,线程间的相互依赖关系主要通过信号和槽机制来实现。这是Qt的核心特性之一,允许对象之间进行通信。在多线程环境中,这种机制尤其有用,因为它可以帮助我们在不同的线程之间发送消息。

以下是一些关于Qt线程间相互依赖关系的关键点:

  1. 信号和槽机制:在Qt中,一个对象(发送者)可以发出一个信号,其他对象(接收者)可以连接到这个信号,以便在信号发出时接收通知。这种机制允许我们在不同的线程之间发送消息,而无需关心线程同步的问题。

  2. 线程安全:Qt的信号和槽机制是线程安全的。这意味着你可以从任何线程发出信号,而Qt将确保它被正确地传递到接收槽。这使得在多线程环境中编程变得更加简单。

  3. 事件循环:每个QThread都有自己的事件循环,可以处理Qt的事件和信号。这意味着你可以在一个线程中发出信号,然后在另一个线程中处理它。这对于实现复杂的线程间通信非常有用。

  4. 移动对象到其他线程:Qt允许你将QObject的子类的实例移动到其他线程。这意味着你可以创建一个对象,在一个线程中使用它,然后将它移动到另一个线程,以在那里继续使用。

总的来说,Qt提供了一种强大而灵活的方式来管理线程间的相互依赖关系。通过信号和槽机制,你可以在不同的线程之间发送消息,而无需担心线程同步的问题。

1.3 设计合理的代码框架

设计合理的代码框架是实现高效多线程编程的关键。在C++和Qt混合使用的环境中,我们需要考虑如何有效地组织和管理线程,以及如何处理线程间的相互依赖关系。以下是一些关键的设计原则和策略:

  1. 明确线程的职责:每个线程都应该有一个明确的职责。这可以帮助我们更好地理解代码的行为,并减少错误和问题的可能性。

  2. 使用适当的同步机制:在多线程环境中,同步是非常重要的。我们需要确保在任何时候,只有一个线程可以访问共享资源。C++和Qt都提供了多种同步机制,如互斥量、条件变量和信号/槽。

  3. 避免线程阻塞:线程阻塞会导致程序的性能下降。我们应该尽量避免在线程中进行可能导致阻塞的操作,如I/O操作或网络请求。如果必须进行这些操作,应该考虑使用异步编程模型。

  4. 合理使用线程池:线程池是一种用于管理线程的工具。它可以帮助我们限制程序中的线程数量,避免线程过多导致的性能问题。

  5. 设计良好的错误处理机制:在多线程环境中,错误处理是非常重要的。我们需要设计一个能够处理各种可能出现的错误情况的机制。

通过遵循这些设计原则和策略,我们可以创建一个强大、灵活且易于维护的多线程应用框架。

二、深入理解C++和Qt线程模型

2.1 C++线程模型

线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。在C++11之前,C++标准库并没有提供线程的支持,开发者需要依赖于操作系统的API或者第三方库来进行多线程编程。然而,从C++11开始,C++标准库引入了线程支持,使得开发者可以直接使用C++标准库来进行多线程编程。


C++线程模型(C++ Thread Model)主要是通过std::thread类来实现的。std::thread类代表一个可执行的线程,它提供了创建线程、移动线程、查询线程状态、终止线程等操作。在C++线程模型中,每一个std::thread对象都对应一个在操作系统中实际存在的线程。


在C++线程模型中,线程的创建主要通过std::thread的构造函数来完成。构造函数接受一个函数或者可调用对象,以及该函数或者可调用对象的参数,然后创建一个新的线程并开始执行该函数或者可调用对象。例如,下面的代码创建了一个新的线程并开始执行函数f:


void f() {
    // ...
}

std::thread t(f);  // 创建一个新的线程并开始执行函数f

2.2 Qt线程模型

Qt是一个跨平台的C++图形用户界面应用程序开发框架,它提供了一套完整的多线程编程接口。在Qt线程模型中,线程的创建、同步和终止都可以通过Qt提供的类和方法来完成,而不需要直接使用操作系统的API或者C++标准库。


Qt线程模型主要是通过QThread类来实现的。QThread类代表一个可执行的线程,它提供了创建线程、移动线程、查询线程状态、终止线程等操作。在Qt线程模型中,每一个QThread对象都对应一个在操作系统中实际存在的线程。


在Qt线程模型中,线程的创建主要通过QThread的start方法来完成。start方法会创建一个新的线程并开始执行QThread的run方法。开发者可以通过重写run方法来定义线程的行为。例如,下面的代码创建了一个新的线程并开始执行MyThread类的run方法:


class MyThread : public QThread {
protected:
    void run() override {
        // ...
    }
};

MyThread t;  // 创建一个新的线程
t.start();   // 开始执行MyThread的run方法

在Qt线程模型中,线程的同步主要通过互斥量(QMutex)和条件变量(QWaitCondition)来实现。此外,Qt还提供了信号槽机制和事件循环,这些高级功能使得线程同步变得更加简单和直观。


在Qt线程模型中,线程的终止主要通过QThread的quit或者terminate方法来完成。quit方法会结束事件循环,然后run方法返回,线程结束执行。terminate方法会立即终止线程,但是这种方法是不安全的,因为它可能会导致资源泄漏或者其他的问题。


总的来说,Qt线程模型提供了一套完整的多线程编程接口,它不仅包含了C++线程模型的所有功能,还提供了信号槽机制、事件循环等高级功能。这些高级功能使得Qt线程模型在很多场景下都比C++线程模型更加方便和强大。

在C++线程模型中,线程的同步主要依赖于互斥量(Mutex)和条件变量(Condition Variable)。互斥量起到保护共享数据的作用,防止多个线程同时访问同一份数据。条件变量则在多个线程之间同步状态,使得一个线程可以等待另一个线程的信号。

至于线程的终止,C++主要通过std::thread的join或者detach方法来完成。join方法会阻塞当前线程,直到对应的线程结束执行。而detach方法则会使对应的线程成为后台线程,并立即返回。

总的来说,C++线程模型提供了一整套多线程编程接口,允许开发者直接使用C++标准库进行多线程编程。但是,C++线程模型并未提供如事件循环、信号槽机制等高级功能,这在一些特定场景下可能导致使用上的不便。

比如,如果你在一个线程中创建了一个定时器,并希望每隔一段时间就执行一次某个函数,那么在C++线程模型中,你可能需要自己编写一个事件循环来处理。而如果使用Qt线程模型,你可以直接使用QTimer类来创建定时器,然后通过信号槽机制来连接定时器的超时信号和你希望执行的函数。

C++线程模型中的线程同步机制相对较低级。虽然互斥量和条件变量在许多情况下都能满足需求,但是在复杂的场景下,使用这两种工具进行线程同步可能变得相当复杂。而Qt线程模型提供了更高级的线程同步机制,如信号槽机制和事件循环,可以大大简化线程同步的操作。

因此,虽然C++线程模型提供了一套完整的多线程编程接口,但在特定场景下,你可能还需要借助其他的库或者框架进行多线程编程。下文我们将介绍Qt线程模型,以及如何在C++和Qt线程模型之间进行互操作。

我们进一步了解一下C++的线程类std::thread。这个类代表一个独立的执行线程,可以并行执行多个函数。当构建与线程关联的std::thread对象时,线程立即开始执行,从传入的顶层函数开始。顶层函数的返回值将被忽略,而且如果它以异常结束,会调用std::terminate。顶层函数可以通过std::promise或者通过修改共享变量(可能需要同步,参见std::mutex与std::atomic)将其返回值或异常传递给调用方。

std::thread对象也可能处于没有关联任何执行线程的状态(例如,被默认构造、移动后、detach后或join后),并且执行线程可能与任何thread对象无关(detach后)。没有两个std::thread对象会表示同一执行线程;std::thread不可复制,但是可以移动。

std::thread类提供了一些重要的成员函数,包括:joinable(检查线程是否可以合并),get_id(返回线程的ID),native_handle(返回底层实现定义的线程句柄),hardware_concurrency(返回实现支持的并发线程数),join(等待线程完成其执行),detach(使线程独立执行),以及swap(交换两个thread对象)。

理解了std::thread的基本概念和特性后,我们就能更好地在项目中使用它,同时也可以更有效地与Qt的QThread类进行混合使用。

2.3 C++和Qt线程模型的比较

在理解了C++和Qt的线程模型之后,我们可以从多个角度对比这两种线程模型,以便更好地理解它们的优缺点和适用场景。


C++线程模型Qt线程模型
线程创建通过std::thread的构造函数创建线程,构造函数接受一个函数或者可调用对象以及其参数。通过QThread的start方法创建线程,需要重写run方法来定义线程的行为。
线程同步主要通过互斥量和条件变量进行线程同步,较为低级。除了提供互斥量和条件变量外,还提供了信号槽机制和事件循环,使得线程同步更加简单和直观。
线程终止通过std::thread的join或者detach方法终止线程。通过QThread的quit或者terminate方法终止线程。
高级功能不提供事件循环、信号槽机制等高级功能。提供事件循环、信号槽机制等高级功能。

从上表可以看出,C++线程模型和Qt线程模型在线程创建、线程同步和线程终止等基本功能上是相似的,但是在高级功能上有较大的差异。C++线程模型更加底层和通用,它可以在任何支持C++11的平台上使用。然而,C++线程模型并没有提供事件循环、信号槽机制等高级功能,这在某些场景下可能会带来不便。


相比之下,Qt线程模型在提供基本功能的同时,还提供了事件循环、信号槽机制等高级功能。这些高级功能使得Qt线程模型在很多场景下都比C++线程模型更加方便和强大。然而,Qt线程模型只能在Qt应用程序中使用,它依赖于Qt库的其他部分,如事件系统和元对象系统。


因此,选择使用C++线程模型还是Qt线程模型,主要取决于你的具体需求。如果你需要在一个Qt应用程序中进行多线程编程,那么Qt线程模型可能是一个更好的选择。如果你需要在一个非Qt应用程序中进行多线程编程,或者你需要在多个平台上进行多线程编程,那么C++线程模型可能是一个更好的选择。


在接下来的部分,我们将介绍如何在C++和Qt线程模型之间进行互操作,以及如何设计一个高效的多线程应用框架。

三、C++和Qt线程间的互操作性

3.1 std::thread与QThread的相互依赖

在深入探讨std::thread(标准线程)与QThread(Qt线程)的相互依赖之前,我们首先需要理解这两种线程模型的基本特性和工作方式。std::thread是C++11引入的线程库,它提供了一种面向对象的线程管理方式,使得我们能够更加方便地创建和管理线程。而QThread则是Qt框架提供的线程管理类,它提供了一种更加高级的线程管理方式,包括信号和槽机制,事件循环等特性。


std::thread和QThread在功能上有很大的相似性,但在实现细节上却有着显著的差异。这些差异主要体现在线程的生命周期管理、线程同步机制、以及错误处理等方面。例如,std::thread在创建线程时需要提供一个函数或者可调用对象,而QThread则需要重写其run()方法。此外,std::thread提供了基本的线程同步机制,如互斥量和条件变量,而QThread则通过信号和槽以及事件循环提供了更高级的线程同步机制。


在实际的项目开发中,我们可能会遇到需要在std::thread中使用QThread的功能,或者在QThread中使用std::thread的功能的情况。这就涉及到了std::thread和QThread的相互依赖问题。例如,我们可能需要在一个std::thread线程中使用QTimer来进行定时操作,但由于QTimer依赖于Qt的事件循环,而std::thread并不支持事件循环,因此这种操作是无法直接实现的。解决这个问题的一种方式是使用QThread来替代std::thread,但这可能会带来其他的问题,如代码的复杂性增加,以及与现有的C++代码的兼容性问题等。


因此,如何在保持代码的简洁性和可维护性的同时,有效地解决std::thread和QThread的相互依赖问题,是我们在设计多线程应用框架时需要考虑的重要问题。在接下来的部分,我们将深入探讨这个问题,并提出一些可能的解决方案。

3.2 在std::thread中使用QTimer的问题(Issues with Using QTimer in std::thread)

在C++的多线程编程中,std::thread(标准线程)是我们常用的一个工具。然而,当我们在Qt环境下进行多线程编程时,我们通常会选择使用QThread(Qt线程)。这是因为QThread提供了一些Qt特有的功能,如信号和槽机制,这在std::thread中是无法实现的。然而,当我们试图在std::thread中使用Qt的一些功能,如QTimer时,我们可能会遇到一些问题。


首先,我们需要理解QTimer的工作原理。QTimer(定时器)是Qt中的一个类,它提供了一种方式来触发一个定时事件。这个定时事件是通过Qt的事件循环(Event Loop)来实现的。事件循环是Qt程序的核心,它负责处理和分发各种事件,如用户输入、窗口更新、网络事件等。QTimer的定时事件就是通过这个事件循环来触发的。


然而,std::thread并不拥有Qt的事件循环。当我们在std::thread中创建一个QTimer并启动它时,由于没有事件循环来触发定时事件,这个QTimer实际上是不会工作的。这就是在std::thread中使用QTimer的主要问题。


那么,我们有没有办法在std::thread中使用QTimer呢?答案是有的,但这需要我们进行一些额外的设置。具体来说,我们需要在std::thread中创建一个QEventLoop(事件循环),并在这个事件循环中启动QTimer。这样,QTimer的定时事件就可以被正确地触发了。然而,这种方法有一个缺点,那就是我们需要手动管理这个事件循环,包括它的启动和停止,这增加了编程的复杂性。


总的来说,虽然在std::thread中使用QTimer是可能的,但由于需要手动管理事件循环,这种方法的复杂性较高。因此,如果可能的话,我们建议在Qt环境下进行多线程编程时,优先考虑使用QThread。

3.3 解决方案和替代选项(Solutions and Alternatives)

面对在std::thread中使用QTimer的问题,我们有多种解决方案和替代选项。下面,我们将详细介绍这些方法,并分析它们的优缺点。


首先,最直接的解决方案就是在std::thread中创建并管理一个QEventLoop(事件循环)。如我们前面所述,QTimer的定时事件是通过Qt的事件循环来触发的。因此,只要我们在std::thread中创建一个事件循环,并在这个事件循环中启动QTimer,QTimer就可以正常工作了。然而,这种方法的缺点是需要手动管理事件循环,包括它的启动和停止,这增加了编程的复杂性。


其次,我们可以考虑使用Qt的线程类QThread。QThread内部已经包含了一个事件循环,因此我们可以直接在QThread中使用QTimer,而无需进行任何额外的设置。此外,QThread还提供了一些Qt特有的功能,如信号和槽机制,这在std::thread中是无法实现的。因此,如果我们的程序已经使用了Qt,那么使用QThread是一个更好的选择。


最后,如果我们的程序需要同时使用std::thread和QThread,我们可以考虑设计一个合理的代码框架,以实现这两种线程的高效协作。具体来说,我们可以将需要使用QTimer的任务放在QThread中执行,而将其他任务放在std::thread中执行。通过这种方式,我们可以避免在std::thread中使用QTimer的问题,同时也可以充分利用std::thread和QThread各自的优点。


总的来说,面对在std::thread中使用QTimer的问题,我们有多种解决方案和替代选项。选择哪种方法取决于我们的具体需求和环境。在实际编程中,我们应根据实际情况,灵活选择和使用这些方法。


四、设计高效的多线程应用框架

4.1 理解上下级关系

在多线程编程中,理解上下级关系(Hierarchical Relationships)是非常重要的。这种关系可以帮助我们更好地组织和管理线程,以提高代码的可读性和可维护性。在C++和Qt中,我们可以通过创建线程树(Thread Trees)来表示这种关系。线程树是一种特殊的数据结构,其中每个节点代表一个线程,父节点代表上级线程,子节点代表下级线程。


在C++中,我们可以使用std::thread类来创建和管理线程。然而,std::thread类并没有提供直接的方式来表示线程之间的上下级关系。这是因为std::thread是基于操作系统的线程API(如POSIX threads或Windows threads)设计的,这些API通常不支持线程之间的层次关系。因此,如果我们想在C++中表示线程之间的上下级关系,我们需要自己设计和实现这种关系。


在Qt中,我们可以使用QThread类来创建和管理线程。与std::thread不同,QThread类提供了一种直接的方式来表示线程之间的上下级关系。这是通过QObject类的父子关系实现的。在Qt中,每个QObject对象都可以有一个父对象和多个子对象。这种父子关系可以用来表示对象之间的所有权关系,也可以用来表示线程之间的上下级关系。当我们创建一个QThread对象时,我们可以指定它的父对象,从而将它添加到线程树中。


然而,虽然QThread类提供了一种直接的方式来表示线程之间的上下级关系,但这并不意味着我们应该总是使用QThread而不是std::thread。事实上,QThread和std::thread各有优势和劣势,我们应该根据具体的需求和情况来选择使用哪个。例如,如果我们需要使用Qt的事件循环和信号槽机制,那么QThread可能是一个更好的选择。如果我们需要使用C++的并发库(如std::async和std::future),那么std::thread可能是一个更好的选择。


总的来说,理解上下级关系是设计高效多线程应用框架的关键。通过理解和使用C++和Qt的线程模型,我们可以更好地组织和管理线程,从而提高代码的可读性和可维护性。

4.2 设计合理的代码框架

设计合理的代码框架是实现高效多线程应用的关键。一个好的代码框架不仅可以提高代码的可读性和可维护性,还可以帮助我们更好地理解和管理线程之间的关系。在这一节中,我们将探讨如何设计一个合理的多线程代码框架。


首先,我们需要确定线程之间的关系。在多线程编程中,线程之间的关系通常可以分为两种类型:独立关系和依赖关系。独立关系的线程可以并行运行,不需要等待其他线程。依赖关系的线程则需要等待其他线程完成某些任务后才能继续运行。我们需要根据应用的需求和线程之间的实际关系来确定线程的关系类型。


其次,我们需要选择合适的线程模型。C++(std::thread)和Qt(QThread)都提供了强大的线程模型,我们可以根据应用的需求和线程之间的关系来选择合适的线程模型。例如,如果我们需要使用Qt的事件循环和信号槽机制,那么QThread可能是一个更好的选择。如果我们需要使用C++的并发库(如std::async和std::future),那么std::thread可能是一个更好的选择。


最后,我们需要设计合理的线程管理策略。线程管理策略是指如何创建、销毁、调度和同步线程的策略。一个好的线程管理策略可以帮助我们更好地利用系统资源,提高应用的性能和响应性。在设计线程管理策略时,我们需要考虑多种因素,如线程的数量、线程的生命周期、线程的优先级、线程的同步和通信机制等。


总的来说,设计合理的代码框架是实现高效多线程应用的关键。通过确定线程之间的关系,选择合适的线程模型,和设计合理的线程管理策略,我们可以构建一个高效、可读、可维护的多线程应用框架。

4.3 实例分析:从底层原理到上层应用

理论知识的学习和理解是重要的,但是将这些理论知识应用到实际问题中去是更为关键的。在这一节中,我们将通过一个实例来分析如何从底层原理到上层应用设计一个高效的多线程应用框架。


假设我们正在开发一个图像处理应用,该应用需要处理大量的图像数据。为了提高处理速度,我们决定使用多线程技术。我们的目标是设计一个高效、可读、可维护的多线程应用框架。


首先,我们需要确定线程之间的关系。在我们的应用中,每个线程都需要处理一部分图像数据,处理完毕后将结果发送给主线程。这种情况下,线程之间的关系是独立的,因为每个线程都可以并行处理自己的数据,不需要等待其他线程。


其次,我们需要选择合适的线程模型。由于我们的应用需要使用Qt的GUI库来显示处理结果,因此我们选择使用QThread作为我们的线程模型。我们可以创建一个QThread子类,重写其run()方法来执行图像处理任务。


最后,我们需要设计合理的线程管理策略。在我们的应用中,我们可以使用一个线程池来管理线程。线程池可以帮助我们控制线程的数量,避免线程的频繁创建和销毁带来的开销。我们可以创建一个QThreadPool对象,使用其start()方法来启动线程,使用其waitForDone()方法来等待所有线程完成。


通过这个实例,我们可以看到,设计一个高效的多线程应用框架并不是一件简单的事情,它需要我们深入理解多线程编程的原理,熟悉使用线程相关的工具和技术,以及具备良好的设计和编程能力。但是,只要我们掌握了这些知识和技能,我们就能够构建出高效、可读、可维护的多线程应用框架。

4.4 架构设计实战展示

以下是更新后的架构图,更明确地展示了QThread,std::thread,QTimer类,观察者模式和策略模式的关系:

在这里插入图片描述

在这个架构图中,我们可以看到图像处理应用的主要组成部分。主线程是一个QThread,负责管理应用的运行和显示处理结果,其中包含一个QTimer用于定时更新处理结果。线程池负责管理图像处理线程,每个图像处理线程是一个被观察者,它可以是std::thread或QThread,它有一个观察者,即std::thread运行的类或包含QTimer的类,并使用了策略模式,其中一种策略是纯C++应用,另一种策略是使用Qt事件循环的类。

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

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

相关文章

chatgpt赋能python:Python如何获取微信聊天记录

Python如何获取微信聊天记录 作为世界上最受欢迎的即时通讯工具之一,微信被大量用户使用。然而,微信聊天记录的备份和管理是一个重要的问题,特别是对于那些需要在工作和个人生活中快速查找重要信息的人来说。 幸运的是,Python编…

Cloud篇——GateWay 网关

1、GateWay是什么 官网讲解: SpringCloud Gateway 是 Spring Cloud 的一个全新项目,基于 Spring 5.0Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。 SpringCloud Gate…

READ-自动驾驶大场景神经渲染

这是一个针对自动驾驶场景的神经渲染方案,提出了一种大规模神经渲染方法来合成自动驾驶场景(READ),这使得通过各种采样方案在PC上合成大规模驾驶场景成为可能。 疑问:文中提到基于nerf的方法和神经渲染方法&#xff0…

kali 2023.2安装、换源、更新、SSH

kali2023版本已经更新了,为了体验新版,下载试用了一下。记录初始的安装过程,以备复习用,不足之处欢迎批评指正。 一、下载 1、官网下载,地址:https://www.kali.org/,因为我准备在VM虚拟机中使用…

chatgpt赋能python:Python如何抓取数据

Python如何抓取数据 介绍 Python是一种功能强大的编程语言,它被广泛使用于网络抓取和数据分析。无论您是想要从网站上抓取数据,还是使用API抓取数据,Python都是一种非常适合的工具。在本文中,我们将介绍Python如何抓取数据&…

WINDOWS权限维持

Meterpreter权限维持 meterpreter中的权限维持技术有两种: persistence(注册表后门)metsvc的后门(服务后门) 1、注册表后门 windows/local/persistence 这个方法是执行vbs脚本,这里很容易被杀软拦截&a…

Android 12.0 系统设置显示主菜单添加屏幕旋转菜单实现旋转屏幕功能

1.前言 在android12.0的系统rom定制化开发中,在对系统设置进行定制开发中,有产品需求要求增加 旋转屏幕功能的菜单,就是在点击旋转屏幕菜单后弹窗显示旋转0度,旋转 90度,旋转180度, 旋转270度针对不同分辨率的无重力感应的大屏设备的屏幕旋转功能的实现, 接下来就来分析…

MySQL数据库 12:约束

约束: 在MySQL中,约束是一种限制数据表中列值的规定。保证数据库中的数据正确,有效性和完整性。MySQL中的约束有以下几种: 1. 主键约束(Primary Key Constraint):主键是用于唯一标识表中每行记…

浅谈Servlet、HTTP

一、Servlet Servlet 是Java Web 开发的规范。任何一个mvc的框架都是servlet发展来的。SpringMVC使用DispatcherServlet拦截所有API请求,自定义注解进行URL匹配。 Servlet层次结构 Setvlet生命周期 1、工作流程 1.Web Client 向Servlet容器(Tomcat&…

Java 实现更新顺序表中的指定元素

一、思路 1.定义一个 pos 变量为要更新的位置,定义一个 value 变量为更新后的数值. 2.顺序表不能是空的,就肯定不可以更新元素. 3.pos位置要合法,要保证 pos 位置是处在顺序表范围内的. 4.更新功能不需要考虑扩容,因为不涉及到元素…

传统制作 VS AI制作,如何一键制作PPT ?

教你如何快速的生成一个可用的 PPT,以及现在比较主流的 ChatGPT PPT 衍生工具推荐。 一、原理 结合AI生成 PPT 的原理其实非常简单, 现有的一些 PPT 软件或者开源工具会提供一种文本格式,我们只需要给出定固定的格式,把内容输入…

分享几个实用的C站AI模型平替网站

分享几个实用的C站AI模型平替网站 部分用户可能没有mofa工具访问Civitai ( C站)下载AI模型,所以给大家分享几款国内版AI模型素材库,无障碍访问下载Stable diffusion模型。 1、LiblibAI 访问速度快,作品墙、有提示词参考,无需登录…

SciencePub学术 | 智能交通类重点SCIEI征稿中

SciencePub学术刊源推荐: 智能交通类SCI&EI征稿中!进展顺利,录用率高,连续十年IF稳定上升。信息如下,录满为止: 一、期刊概况: 【期刊简介】IF:4.0-4.5↑, JCR 2区,…

剪映自动打关键帧

牙叔教程 简单易懂 这是给单张图片打关键帧的教程, 给图片打关键帧有四个步骤 鼠标点选图片打起始帧跳转到图片末尾打结束帧 打帧是一件很费手的事情, 所以我写了个自动化的代码, 专门用来打关键帧, 使用的软件是 AutoHotkey 关键帧参数的详细解释 剪映 自动打关键帧 AutoH…

chatgpt赋能python:Python中如何精确表示小数

Python中如何精确表示小数 在日常的数学计算过程中,小数是不可避免的。然而,由于计算机在存储和处理小数时的固有限制,会导致精度上的问题。Python作为一种通用的编程语言,也具有这样的限制。但是,在Python中&#xf…

基于层次的聚类算法

尽管基于划分的聚类算法能够实现把数据集划分成指定数量的簇,但是在某些情况下,需要把数据集划分成不同层上的簇:比如,作为一家公司的人力资源部经理,你可以把所有的雇员组织成较大的簇,如主管、经理和职员…

三维重建 医学图像的可视化 PyQt Python VTK 四视图(横断面,冠状面,矢状面,3D)

本文实现了 Python C 版本 的 四视图,横断面,冠状面,矢状面,3D 主要功能: 1:可以通过进度条换层 2:鼠标双击放大/缩小窗口 3:按住鼠标中键拖动图像 4:鼠标右键滑动放大/缩小图像 效果: 视频&#…

数据库期末复习(7.1) 查询执行

目标 了解各种查询执行的方法和记住各种查询执行的IO代价,了解支持算法最少的空间(页数多少)。 一趟归并排序的代价和改进方案笔记 数据库 查询执行(1) 多路归并_旅僧的博客-CSDN博客 创建归并段过程的IO代价是2B(R) 并且会在页面中新开辟一段run为了存放已经排好序的归并…

c语言的一些小题目(初阶),持续分享......

文章目录 1.打印杨辉三角形 2.打印X形图案 3.打印菱形 4.字符串左旋 5.倒置字符串 文章内容 1.杨辉三角形是一道非常经典的题目,观察下面的图片中红色与蓝色方块的关系我们不难发现,两个红色方框里的数字相加等于蓝色方框里的数字,找到…

十、RGBA数据转NV21格式存储

1、介绍 首先为什么要去了解RGBA转NV21格式的,因为在软编码X264的时候就需要yuv格式作为输入源进行编码。 NV21格式的回顾:也是YUV420SP格式,存储两个plane,Y,VU交叉存储,内存大小为w * h w * h/ 4 * 2w…