首页 > 其他分享 >Qt QQueue 详解:从底层原理到高级用法

Qt QQueue 详解:从底层原理到高级用法

时间:2024-01-30 10:58:22浏览次数:26  
标签:QQueue std Qt 队列 queue 详解 QList

引言:QQueue的重要性与简介
  在现代软件开发中,数据结构和算法扮演着至关重要的角色。它们为程序员提供了处理各种不同场景下数据的有效方法。QQueue(队列)是一种常见且实用的数据结构,它在许多应用中都发挥着关键作用。本文将简要介绍QQueue的重要性和简介。

  队列(Queue)是一种遵循先进先出(FIFO,First In First Out)原则的线性数据结构。在这种结构中,元素的添加(入队)和移除(出队)操作分别在队列的尾部和头部进行。这种特性使得队列在处理一些需要按顺序执行任务的场景中表现出优越性。

  QQueue,源自Qt框架,是一个C++实现的队列类,提供了丰富的API以实现队列的各种操作。Qt是一个跨平台的C++应用程序开发框架,广泛用于开发GUI应用程序、嵌入式和移动应用程序。QQueue继承自QList,因此可以方便地利用QList的功能实现队列的基本操作。

QQueue的重要性主要表现在以下几个方面:

任务调度:在操作系统或多线程应用中,QQueue可用于实现任务调度器,确保任务按照预定的顺序执行,避免资源竞争和死锁问题。
消息队列:在分布式系统或网络应用中,QQueue可以作为消息队列用于缓存和传输消息,确保消息的有序到达和处理。
数据缓冲:在数据处理和传输过程中,QQueue可以作为缓冲区,允许数据在生产者和消费者之间异步传输,提高系统的吞吐量和响应速度。
事件处理:在GUI应用程序中,QQueue可以用于实现事件队列,确保用户界面按顺序响应用户的操作。
综上所述,QQueue作为一种实用的数据结构,广泛应用于不同领域的软件开发。了解QQueue的重要性和基本概念,将有助于开发者更好地利用这一工具解决实际问题。

QQueue的常用接口
  QQueue是Qt库中的一个容器类,它是一个先进先出(FIFO)的队列,用于存储具有相同类型的数据。QQueue提供了一些常用接口,使得对队列进行操作变得非常简单。

  下面是QQueue的一些常用接口及其详细介绍:

  1. QQueue():构造函数,创建一个空的队列。
  2. ~QQueue():析构函数,销毁队列及其所有元素。
  3. void enqueue(const T &value):将值value添加到队列的末尾。
  4. T dequeue():从队列的头部移除并返回第一个元素。如果队列为空,这个函数的行为是未定义的。
  5. T &head():返回队列头部元素的引用。如果队列为空,这个函数的行为是未定义的。
  6. const T &head() const:返回队列头部元素的只读引用。如果队列为空,这个函数的行为是未定义的。
  7. bool isEmpty() const:返回队列是否为空的布尔值。
  8. int size() const:返回队列中的元素个数。
  9. void clear():清空队列中的所有元素。
  10. bool contains(const T &value) const:检查队列是否包含特定值value。
  11. int count(const T &value) const:返回队列中特定值value的个数。
  12. T &first():返回队列中第一个元素的引用。如果队列为空,这个函数的行为是未定义的。
  13. const T &first() const:返回队列中第一个元素的只读引用。如果队列为空,这个函数的行为是未定义的。
  14. T &last():返回队列中最后一个元素的引用。如果队列为空,这个函数的行为是未定义的。
  15. const T &last() const:返回队列中最后一个元素的只读引用。如果队列为空,这个函数的行为是未定义的。

  以上就是QQueue的常用接口及其介绍。在使用QQueue时,确保在对队列执行操作时了解接口的功能和限制,以避免出现未定义的行为。

  下面是一个使用C++和Qt库的简单示例,展示了如何使用QQueue及其所有常用操作:

 1 #include <QCoreApplication>
 2 #include <QQueue>
 3 #include <QDebug>
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     QCoreApplication a(argc, argv);
 8 
 9     // 1. 创建一个空的QQueue对象
10     QQueue<int> queue;
11 
12     // 2. 入队元素
13     queue.enqueue(10);
14     queue.enqueue(20);
15     queue.enqueue(30);
16 
17     // 3. 获取队列大小
18     qDebug() << "Queue size:" << queue.size(); // 输出:Queue size: 3
19 
20     // 4. 检查队列是否为空
21     qDebug() << "Queue is empty:" << queue.isEmpty(); // 输出:Queue is empty: false
22 
23     // 5. 查看队列的头部元素
24     qDebug() << "Queue head:" << queue.head(); // 输出:Queue head: 10
25 
26     // 6. 出队元素
27     int firstElement = queue.dequeue();
28     qDebug() << "Dequeued element:" << firstElement; // 输出:Dequeued element: 10
29 
30     // 7. 获取队列中的第一个和最后一个元素
31     qDebug() << "First element:" << queue.first(); // 输出:First element: 20
32     qDebug() << "Last element:" << queue.last(); // 输出:Last element: 30
33 
34     // 8. 检查队列是否包含特定值
35     qDebug() << "Queue contains 20:" << queue.contains(20); // 输出:Queue contains 20: true
36 
37     // 9. 计算队列中特定值的个数
38     qDebug() << "Count of 20 in queue:" << queue.count(20); // 输出:Count of 20 in queue: 1
39 
40     // 10. 清空队列
41     queue.clear();
42     qDebug() << "Queue size after clear:" << queue.size(); // 输出:Queue size after clear: 0
43 
44     return a.exec();
45 }

  以上代码演示了如何使用QQueue的各种操作,包括构造、入队、出队、获取队列大小、检查是否为空、查看头部元素、获取队列中的第一个和最后一个元素、检查队列是否包含特定值、计算特定值的个数以及清空队列。

QQueue 的使用场景
  QQueue 是 Qt 库中的一个容器类,它表示一个双端队列(double-ended queue,简称 deque)。QQueue 提供了在队列两端进行高效插入和删除操作的功能。QQueue 继承自 QList,可以在首尾方便地添加和删除元素。下面是一些 QQueue 的使用场景:

  任务队列:可以用 QQueue 来管理一个任务队列,将待处理的任务添加到队列中,然后依次处理并移除已完成的任务。这种场景下,可以将 QQueue 当作一个先进先出(FIFO)数据结构来使用。
  消息队列:在多线程应用中,可以使用 QQueue 存储线程间通信的消息。主线程将消息添加到队列中,子线程从队列中取出消息并处理。这种场景下,需要确保对队列的访问是线程安全的,可以通过加锁等机制实现。
  数据缓冲:在处理大量数据时,可以使用 QQueue 作为缓冲区,存储已经处理过的数据,以便在需要时能够快速访问。例如,在处理实时音频或视频数据时,可以将已处理的数据帧存入 QQueue 中,以备后续的播放或分析使用。
  编程算法:QQueue 可以用于实现一些编程算法,如宽度优先搜索(BFS)等。通过将待处理的节点添加到队列中,可以保证算法的执行顺序。
  事件处理:在事件驱动的程序中,可以使用 QQueue 存储待处理的事件。当事件发生时,将事件对象添加到队列中,然后逐个处理并删除队列中的事件。
  迭代器:遍历QQueue中的元素(Iterators: Traversing Elements in QQueue)
  QQueue 是 Qt 库中的一个容器类,实现了先进先出(FIFO)队列。要遍历 QQueue 中的元素,可以使用迭代器。以下是遍历 QQueue 中元素的不同方法:

1. 常规索引遍历
由于 QQueue 是 QList 的子类,因此可以使用索引访问元素:

1 QQueue<int> queue;
2 queue.enqueue(1);
3 queue.enqueue(2);
4 queue.enqueue(3);
5 
6 for (int i = 0; i < queue.size(); ++i) {
7     qDebug() << queue.at(i);
8 }

2. 基于范围的 for 循环(C++11 及以上)

1 QQueue<int> queue;
2 queue.enqueue(1);
3 queue.enqueue(2);
4 queue.enqueue(3);
5 
6 for (const int &value : queue) {
7     qDebug() << value;
8 }

3. 使用 STL 样式迭代器

1 QQueue<int> queue;
2 queue.enqueue(1);
3 queue.enqueue(2);
4 queue.enqueue(3);
5 
6 QQueue<int>::iterator it;
7 for (it = queue.begin(); it != queue.end(); ++it) {
8     qDebug() << *it;
9 }

4. 使用 const 迭代器(只读访问)

1 QQueue<int> queue;
2 queue.enqueue(1);
3 queue.enqueue(2);
4 queue.enqueue(3);
5 
6 QQueue<int>::const_iterator cit;
7 for (cit = queue.constBegin(); cit != queue.constEnd(); ++cit) {
8     qDebug() << *cit;
9 }

  以上是遍历 QQueue 中元素的不同方法。根据需要和编程风格,可以选择任何一种方法来遍历 QQueue 中的元素。在只读访问情况下,建议使用 const 迭代器,因为它提供了更好的类型安全和性能。

QQueue的性能优化
  QQueue 是 Qt 容器类之一,它实现了一个先进先出(FIFO)的队列。QQueue 是 QList 的子类,因此它继承了 QList 的许多特性。为了优化 QQueue 的性能,可以采取以下几个方面的措施:

  利用 QList 的特性:QQueue 的底层实现基于 QList,所以可以利用 QList 的性能优势。QList 的内存分配策略使得在队列的头部和尾部插入和删除元素具有较高效率。因此,当使用 QQueue 时,尽量避免在队列中间进行插入和删除操作。
  预分配内存:如果可以预估队列的最大大小,那么可以使用 QQueue::reserve() 函数预先分配内存。这将有助于减少内存分配和释放的开销,提高性能。
  避免频繁的内存分配:在频繁地向队列添加和删除元素时,避免频繁的内存分配和释放。可以考虑使用对象池或其他内存管理技术来重用对象,从而提高性能。
  使用 const 成员函数:在遍历队列或访问队列元素时,使用 const 成员函数(如 constFirst() 和 constLast())可以避免不必要的拷贝操作,提高性能。
  考虑使用其他容器:在某些特定场景下,QQueue 可能不是性能最优的选择。例如,如果需要处理大量连续内存访问操作,可以考虑使用 QVector。同样,如果需要在列表中间频繁地插入和删除元素,  QLinkedList 可能是更好的选择。根据实际需求选择合适的容器类,以实现最佳性能。
  总之,在使用 QQueue 时,可以通过充分利用 QList 的特性、预分配内存、避免频繁的内存分配、使用 const 成员函数以及根据需求选择合适的容器类等方法来优化性能。

使用Queue可能遇到的问题和解决方案.
  使用 Queue(队列)时,可能会遇到以下问题。以下是相应的解决方案:

  问题:队列满了,无法继续添加元素。 解决方案:可以考虑动态调整队列的大小,或者在添加新元素之前先检查队列是否已满。如果队列已满,可以选择等待队列中的元素被消费,或者删除队首元素以为新元素腾出空间。
  问题:队列空了,无法获取元素。 解决方案:在尝试从队列中获取元素之前,先检查队列是否为空。如果队列为空,可以选择等待新元素添加到队列中,或者采取其他处理措施。
  问题:多线程环境下的竞争条件和数据不一致。 解决方案:在多线程环境下使用队列时,需要确保对队列的操作是线程安全的。可以使用互斥锁(例如 QMutex)或信号量(例如 QSemaphore)来保护对队列的访问,以避免竞争条件和数据不一致。
  问题:队列的性能不佳,导致程序运行缓慢。 解决方案:优化队列的实现,以提高性能。例如,可以使用循环队列(circular buffer)来减少内存分配和数据移动。此外,可以考虑使用无锁队列(lock-free queue)或其他高效的队列实现来提高并发性能。
  问题:队列元素的类型不匹配。 解决方案:确保队列中存储的元素类型与预期相符。可以使用 C++ 的模板类或 Qt 的模板容器类(如 QQueue)来实现类型安全的队列。
  问题:内存泄漏。 解决方案:确保在从队列中删除元素时正确释放内存。如果队列存储的是对象指针,需要在删除元素时手动释放内存。可以使用智能指针(如 QSharedPointer)来自动管理内存,避免内存泄漏。
  通过应对这些常见问题,可以确保队列在实际项目中的正确使用和高效运行。在使用队列时,要充分了解其特点和局限,以便做出正确的决策。

QQueue的优缺点
  QQueue 是 Qt 数据结构中的一个队列容器类,它提供了队列(先进先出,FIFO)的数据存储和操作方式。QQueue 是基于 QList 实现的,因此它的优缺点与 QList 的优缺点有很大关联。下面我们分析一下 QQueue 的优缺点:

优点:

  简单易用:QQueue 提供了简洁的 API,使用起来非常方便。例如,enqueue() 和 dequeue() 等操作可以方便地完成队列的入队和出队操作。
  动态扩展:QQueue 会根据需要动态地调整内存分配,能够有效地管理内存资源。
  高效的随机访问:由于基于 QList 实现,QQueue 可以在常数时间内完成随机访问操作。
  与其他 Qt 容器兼容:QQueue 可以与其他 Qt 容器类(如 QList、QVector 等)方便地进行互操作,提高代码的通用性和可重用性。
缺点:

  性能受限:对于大量连续数据操作,QQueue 的性能可能不如 QVector 或其他基于数组的容器,尤其是在内存分配和数据拷贝方面。
  非线程安全:QQueue 本身并不是线程安全的。如果需要在多线程环境中使用 QQueue,开发者需要自行添加同步机制以保证线程安全。
  不适合大规模数据存储:由于 QQueue 是基于 QList 实现的,当数据量非常大时,可能会导致内存碎片问题。在这种情况下,使用 QVector 或 QLinkedList 可能是更好的选择。
总结:

  QQueue 作为一个队列容器类,在满足队列操作需求的同时,也具有一定的优缺点。开发者需要根据实际应用场景和需求,权衡 QQueue 的优缺点,来决定是否使用 QQueue 或其他更适合的容器类。

QQueue和std::queue
  QQueue 和 std::queue 都是实现了队列(Queue)数据结构的容器类。队列是一种先进先出(FIFO, First In First Out)的数据结构。尽管它们都提供了队列的基本功能,但在底层实现、接口和特性方面存在一些差异。以下是 QQueue 和 std::queue 之间的主要差异:

底层实现:
  QQueue:QQueue 是基于 QList 实现的,它封装了 QList 的操作来提供队列所需的 enqueue、dequeue 和 head 功能。QList 的底层实现是一个动态数组,支持快速访问和修改元素。
  std::queue:std::queue 是一个容器适配器,它可以基于不同的底层容器实现,如 std::deque、std::list 等。默认情况下,std::queue 使用 std::deque 作为底层容器。
接口与功能:
  QQueue:QQueue 提供了一些 Qt 特有的接口,如 enqueue()、dequeue() 和 head() 等。此外,QQueue 还提供了许多 QList 的其他功能,例如迭代器支持、元素访问、查找等。
std::queue:std::queue 提供了标准 C++ 接口,如 push()、pop() 和 front() 等。与 QQueue 相比,std::queue 的功能相对简单,主要关注队列的基本操作。
内存管理与性能:
  QQueue:由于基于 QList,QQueue 的内存管理和性能特性与 QList 类似。QList 在大部分场景下表现良好,但在大量元素插入和删除时,可能会导致内存碎片。
std::queue:std::queue 的内存管理和性能取决于底层容器的实现。默认的底层容器 std::deque 在大多数场景下表现出良好的性能和内存管理。当然,你可以选择其他底层容器以满足特定需求。
跨平台与兼容性:
  QQueue:QQueue 是 Qt 框架的一部分,具有良好的跨平台支持。对于已经使用 Qt 进行开发的项目,使用 QQueue 有助于保持代码的一致性和可读性。
std::queue:std::queue 是 C++ 标准库的一部分,具有广泛的兼容性。对于不依赖于 Qt 的项目或需要与其他 C++ 代码进行交互的场景,std::queue 可能是更好的选择。
  总的来说,QQueue 和 std::queue 都是实现队列数据结构的有效工具。

  在以下代码示例中,我们将分别使用QQueue和std::queue对相同的数据执行一系列操作,并比较它们在各种操作上的性能。为了测量操作的执行时间,我们将使用C++11的std::chrono库。

 1 #include <QQueue>
 2 #include <queue>
 3 #include <iostream>
 4 #include <random>
 5 #include <chrono>
 6 
 7 // 测试用数据量
 8 const int testDataSize = 100000;
 9 
10 int main() {
11     QQueue<int> qQueue;
12     std::queue<int> stdQueue;
13 
14     // 随机数生成器
15     std::random_device rd;
16     std::mt19937 gen(rd());
17     std::uniform_int_distribution<> dis(1, 100);
18 
19     // 将随机数添加到队列
20     for (int i = 0; i < testDataSize; ++i) {
21         int randomValue = dis(gen);
22         qQueue.enqueue(randomValue);
23         stdQueue.push(randomValue);
24     }
25 
26     // 测试QQueue的出队操作性能
27     auto start = std::chrono::high_resolution_clock::now();
28     while (!qQueue.isEmpty()) {
29         qQueue.dequeue();
30     }
31     auto end = std::chrono::high_resolution_clock::now();
32     auto qQueueDuration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
33     std::cout << "QQueue dequeue time: " << qQueueDuration << " microseconds" << std::endl;
34 
35     // 测试std::queue的出队操作性能
36     start = std::chrono::high_resolution_clock::now();
37     while (!stdQueue.empty()) {
38         stdQueue.pop();
39     }
40     end = std::chrono::high_resolution_clock::now();
41     auto stdQueueDuration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
42     std::cout << "std::queue pop time: " << stdQueueDuration << " microseconds" << std::endl;
43 
44     return 0;
45 }

  在此示例中,我们首先生成了一组随机整数,并将它们添加到QQueue和std::queue中。然后,我们分别测量QQueue和std::queue出队操作的执行时间,并将结果以微秒为单位输出。

  请注意,此示例提供的性能比较可能因系统、编译器设置和运行时条件而有所不同。在实际项目中,建议针对您的特定用例和环境对容器进行性能评估。

高级用法:QQueue 中的算法与功能(Advanced Usage: Algorithms and Functions in QList)
  注意:在问题中您提到了QQueue,但在主题中写了QList。为了回答您的问题,这里我们将讨论QQueue中的高级算法和功能。

  QQueue是一个FIFO(先进先出)数据结构,主要用于解决特定类型的问题,例如任务调度或事件循环等。以下是一些在QQueue中使用高级算法和功能的示例:

使用QQueue实现简单的任务调度器:

 1 #include <QQueue>
 2 #include <QString>
 3 #include <iostream>
 4 
 5 struct Task {
 6     QString name;
 7     int priority;
 8 };
 9 
10 void processTask(const Task& task) {
11     std::cout << "Processing task: " << task.name.toStdString() << ", priority: " << task.priority << std::endl;
12 }
13 
14 int main() {
15     QQueue<Task> taskQueue;
16 
17     // Add tasks to the queue
18     taskQueue.enqueue({"Task 1", 1});
19     taskQueue.enqueue({"Task 2", 2});
20     taskQueue.enqueue({"Task 3", 3});
21 
22     // Process tasks in the order they were added
23     while (!taskQueue.isEmpty()) {
24         Task task = taskQueue.dequeue();
25         processTask(task);
26     }
27 
28     return 0;
29 }

  在这个示例中,我们使用QQueue实现了一个简单的任务调度器,按照添加任务的顺序处理任务。

使用QQueue实现广度优先搜索(BFS):
  广度优先搜索(BFS)是一种常用的树或图结构遍历方法。使用QQueue,您可以轻松地实现BFS。以下是一个使用QQueue在树结构中进行BFS的示例:

 1 #include <QQueue>
 2 #include <QList>
 3 #include <iostream>
 4 
 5 struct TreeNode {
 6     int value;
 7     QList<TreeNode*> children;
 8 };
 9 
10 void bfs(TreeNode* root) {
11     QQueue<TreeNode*> queue;
12     queue.enqueue(root);
13 
14     while (!queue.isEmpty()) {
15         TreeNode* node = queue.dequeue();
16         std::cout << "Visiting node: " << node->value << std::endl;
17 
18         for (TreeNode* child : node->children) {
19             queue.enqueue(child);
20         }
21     }
22 }
23 
24 int main() {
25     // Build a sample tree
26     TreeNode node1{1, {}};
27     TreeNode node2{2, {}};
28     TreeNode node3{3, {}};
29     TreeNode node4{4, {}};
30     TreeNode node5{5, {}};
31 
32     node1.children = {&node2, &node3};
33     node2.children = {&node4, &node5};
34 
35     // Perform BFS on the tree
36     bfs(&node1);
37     return 0;
38 }

  在这个示例中,我们使用QQueue遍历树结构并执行广度优先搜索。

  这些示例演示了如何在不同场景下使用QQueue高级功能。当需要处理特定类型的问题时,请根据实际需求选择合适的数据结构。同时,不要忘了在使用C++算法时确保QQueue中的数据类型支持相应的操作。

实战案例:QQueue在实际项目中的应用(Practical Examples: QQueue Real-World Projects)
  QQueue 是 Qt 库中的一个容器类,它实现了一个先进先出(FIFO)队列。在实际项目中,QQueue 可以用于处理需要按顺序执行的任务,例如事件处理、消息传递等。

示例1:事件处理
  假设我们正在开发一个事件驱动的应用程序,需要处理用户输入、系统事件等。我们可以使用 QQueue 来存储和处理这些事件。

  首先,创建一个 Event 类来存储事件信息:

 1 class Event {
 2 public:
 3     enum Type {
 4         KeyPress,
 5         MouseClick,
 6         SystemEvent,
 7         // 其他类型的事件
 8     };
 9 
10     Event(Type type) : m_type(type) {}
11 
12     Type type() const { return m_type; }
13 
14 private:
15     Type m_type;
16 };

然后,创建一个 QQueue 来存储事件:

QQueue<Event> eventQueue;

当有新事件产生时,将其添加到队列中:

1 void onNewEvent(const Event &event) {
2     eventQueue.enqueue(event);
3 }

在应用程序的主循环中,处理并删除队列中的事件:

1 void processEvents() {
2     while (!eventQueue.isEmpty()) {
3         Event event = eventQueue.dequeue();
4         handleEvent(event);
5     }
6 }

示例2:消息传递系统

  在一个多线程应用程序中,我们可能需要在不同线程之间传递消息。我们可以使用 QQueue 和互斥锁(QMutex)来实现一个线程安全的消息队列。

  首先,创建一个 Message 类来存储消息数据:

 1 class Message {
 2 public:
 3     Message(int id, const QString &content)
 4         : m_id(id), m_content(content) {}
 5 
 6     int id() const { return m_id; }
 7     QString content() const { return m_content; }
 8 
 9 private:
10     int m_id;
11     QString m_content;
12 };

接着创建一个线程安全的消息队列类:

 1 class ThreadSafeQueue {
 2 public:
 3     void enqueue(const Message &message) {
 4         QMutexLocker locker(&m_mutex);
 5         m_queue.enqueue(message);
 6     }
 7 
 8     Message dequeue() {
 9         QMutexLocker locker(&m_mutex);
10         return m_queue.dequeue();
11     }
12 
13     bool isEmpty() const {
14         QMutexLocker locker(&m_mutex);
15         return m_queue.isEmpty();
16     }
17 
18 private:
19     QQueue<Message> m_queue;
20     mutable QMutex m_mutex;
21 };

现在,我们可以在多个线程之间安全地传递消息:

 1 ThreadSafeQueue messageQueue;
 2 
 3 // 生产者线程
 4 void producerThread() {
 5     Message message(1, "Hello, World!");
 6     messageQueue.enqueue(message);
 7 }
 8 
 9 // 消费者线程
10 void consumerThread() {
11     while (!messageQueue.isEmpty()) {
12         Message message = messageQueue.dequeue();
13         processMessage(message);
14     }
15 }

  在这些示例中,我们展示了如何在实际项目中使用 QQueue。通过根据具体需求选择合适的数据结构,我们可以简化代码并提高应用程序的性能。

线程安全性与 QQueue 的并发使用(Thread Safety and Concurrent Usage of QQueue )
   Qt容器类的线程安全性因容器而异。就QQueue而言,它并不是线程安全的,因此在多个线程之间共享和同时访问QQueue时,必须小心。为了在多线程环境中安全地使用QQueue,可以使用互斥量(QMutex)或其他同步原语来确保同一时间只有一个线程访问QQueue。以下是一个示例,演示了如何在多线程环境中使用QMutex保护QQueue的访问:

 1 #include <QMutex>
 2 #include <QQueue>
 3 #include <QThread>
 4 #include <iostream>
 5 
 6 QQueue<int> sharedQueue;
 7 QMutex mutex;
 8 
 9 void enqueue(int value) {
10     QMutexLocker locker(&mutex);
11     sharedQueue.enqueue(value);
12 }
13 
14 int dequeue() {
15     QMutexLocker locker(&mutex);
16 
17     if (!sharedQueue.isEmpty()) {
18         return sharedQueue.dequeue();
19     }
20     return -1; // 或者其他表示队列为空的值
21 }
22 
23 class Producer : public QThread {
24 public:
25     void run() override {
26         for (int i = 0; i < 10; ++i) {
27             enqueue(i);
28             std::cout << "Produced: " << i << std::endl;
29             msleep(100);
30         }
31     }
32 };
33 
34 class Consumer : public QThread {
35 public:
36     void run() override {
37         for (int i = 0; i < 10; ++i) {
38             int value = dequeue();
39             std::cout << "Consumed: " << value << std::endl;
40             msleep(100);
41         }
42     }
43 };
44 
45 int main() {
46     Producer producer;
47     Consumer consumer;
48 
49     producer.start();
50     consumer.start();
51 
52     producer.wait();
53     consumer.wait();
54 
55     return 0;
56 }

  在这个示例中,我们定义了一个生产者线程和一个消费者线程。生产者线程将数据添加到共享QQueue中,而消费者线程从QQueue中读取数据。我们使用QMutex和QMutexLocker来确保在访问共享  QQueue时不会发生竞态条件。在enqueue()和dequeue()函数中,我们使用QMutexLocker对QMutex进行加锁,确保同一时间只有一个线程可以访问QQueue。QMutexLocker在作用域结束时自动解锁互斥量,因此不需要手动解锁。

  这个示例中的方案可以确保在多线程环境中QQueue的安全访问。然而,根据实际需求和场景,您可能需要选择更高效或适合的并发数据结构。例如,Qt Concurrent模块提供了一些线程安全的数据结构和功能,可以在并发编程中使用。

QQueue的性能分析:查找、插入与删除操作
  QQueue 的性能分析:查找、插入与删除操作 (Performance Analysis of QQueue: Search, Insertion, and Deletion)

  QQueue 是 Qt 提供的一种容器类,它实现了一个先进先出(FIFO)的队列。QQueue 是 QList 的子类,所以在分析性能时,我们需要关注 QList 的性能特点。

查找操作
  QQueue 的查找操作主要依赖于 QList 的查找性能。QList 使用连续内存块存储元素,因此它在随机访问的情况下具有很好的性能。QQueue 的随机访问时间复杂度是 O(1),即常数时间。然而,如果需要在 QQueue 中进行顺序查找,时间复杂度将是 O(n),其中 n 是队列中元素的数量。

插入操作
  QQueue 的插入操作主要涉及两种情况:在队列头部插入和在队列尾部插入。由于 QList 的实现,QQueue 在队列尾部插入元素的平均时间复杂度是 O(1)。然而,在队列头部插入元素时,时间复杂度将是 O(n),因为需要移动队列中的所有元素以保持顺序。

删除操作
  类似于插入操作,QQueue 的删除操作也涉及队列头部和尾部的情况。从队列尾部删除元素的平均时间复杂度是 O(1)。但从队列头部删除元素时,时间复杂度将是 O(n),因为需要移动队列中的所有元素以保持顺序。

  综上所述,QQueue 在查找、插入和删除操作方面的性能如下:

  • 查找:随机访问为 O(1),顺序查找为 O(n)
  • 插入:队尾插入为 O(1),队头插入为 O(n)
  • 删除:队尾删除为 O(1),队头删除为 O(n)

  因此,QQueue 在进行队列头部和尾部的插入和删除操作时性能较好,但在头部插入和删除元素时性能较差。在实际应用中,需要根据使用场景选择合适的容器类。如果需要频繁进行头部插入和删除操作,可以考虑使用 QLinkedList,因为它在这些操作上具有更好的性能表现。

QT各版本中QQueue的变化
  从 Qt 5 到 Qt 6,QQueue 在整体功能和用法上并没有显著变化。QQueue 仍然是一个基于 QList 实现的双端队列(双向队列),提供了对队列头部和尾部的快速访问。作为一个先进先出(FIFO)数据结构,QQueue 在许多场景中,如任务调度、事件处理等,发挥了重要作用。

  虽然 QQueue 的主要功能在 Qt 5 和 Qt 6 之间保持一致,但在 Qt 库的其他部分,特别是 QList 的实现方面,有所变化。在 Qt 5 中,QList 的实现基于一个间接数组(indirect array),而在 Qt 6 中,QList 的实现已经更改为基于 QArrayData,与 QVector 的实现更加接近。这意味着 Qt 6 中的 QList 和 QVector 具有类似的性能特性,而 QQueue 作为基于 QList 的容器,其性能特性也相应地发生了改变。

  尽管有这些底层实现的变化,QQueue 在 Qt 5 和 Qt 6 之间的迁移过程中,对于开发者而言,通常是平滑的。开发者在使用 QQueue 时,可以依赖其稳定的 API 和功能特性,而不需要担心底层实现的具体细节。

  总之,在 Qt 5 和 Qt 6 之间,QQueue 的功能和用法保持一致。主要的变化发生在底层实现,特别是与 QList 的关系上。这些变化对于开发者而言通常是透明的,迁移过程相对简单。如果您在使用 QQueue,可以放心地继续使用,享受 Qt 框架带来的便利和性能优化。

标签:QQueue,std,Qt,队列,queue,详解,QList
From: https://www.cnblogs.com/ybqjymy/p/17996639

相关文章

  • fuser命令详解
      fuser-mv作用 fuser命令是用来显示所有正在使用着指定的file、filesystem或者sockets的进程信息。具体来说,fuser-mv的作用如下:参数-m:指定一个被加载的文件系统或一个被加载的块设备。参数-v:显示进程的详细信息。因此,fuser-mv的作用是显示正在使用指定文件系统......
  • [Qt-ColorEditor] Qt颜色编辑器,QColorDialog的优化版,支持RGB和HSV等多种方式选色
    外观分享一下我实现的颜色编辑器,主要原因是Qt的QColorDialog功能较少没法满足需求,目前已经在zeno中使用了,由于zeno有自己的样式表,所以在zeno里长这样:如果不加样式表的话长这样:功能srgb切换颜色轮选色颜色文字选色颜色滑动条选色,RGB和HSV上一个/当前颜色切换,这个主要......
  • Unity3D DrawCall和openGL、光栅化等有何内在联系详解
    Unity3D是一款跨平台的游戏引擎,广泛应用于游戏开发领域。在Unity3D中,DrawCall是一个重要的概念,它与OpenGL、光栅化等技术有着密切的内在联系。本文将详细解释DrawCall的概念,并给出相关技术的详细解释和代码实现。对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础......
  • YOLOv5代码详解1(train.py)
    YOLOv5代码详解(第一部分)1.train.py1.1使用nvidia的apex接口计算混合精度训练1.2获取文件路径1.3获取数据路径1.4移除之前的结果1.5创建模型1.6检查训练和测试图片尺寸1.7设置优化器参数1.8加载预训练模型和权重,并写入训练结果到results.txt1.9把混合精度......
  • 小项目:使用MQTT上传温湿度到Onenet服务器
    前言我们之前分别编写了DHT11、ESP8266和MQTT的代码,现在我们将它们仨整合在一起,来做一个温湿度检测小项目。这个项目可以实时地将DHT11传感器获取到的温湿度数据上传到OneNET平台。通过登录OneNET,我们随时随地可以查看温湿度数据。这种环境监测项目的应用场景有很多,其中......
  • Markdown语法详解--Typora编辑器
    推荐使用的编辑器:typoraMarkdown文件以.md结尾1.通过#来规范标题,#:代表一级标题##:代表二级标题###:代表三级标题####:代表四级标题2.通过*来改变字体*字体*:代表斜体**字体**:代表加粗***字体***:代表加粗且斜体~~字体~~:删除线3.引用效果>+空格4.分割线---或***5.图......
  • 深入理解 Flink(六)Flink Job 提交和 Flink Graph 详解
    FlinkProgram编程套路回顾1、获取执行环境对象StreamExecutionEnvironmentenv=StreamExecutionEnvironment.getExecutionEnvironment();2、通过执行环境对象,注册数据源Source,得到数据抽象DataStreamds=env.socketTextStream(...)3、调用数据抽象的各种Transformation......
  • 详解module ‘yaml‘ has no attribute ‘FullLoader‘
    详解module'yaml'hasnoattribute'FullLoader'在使用Python中的YAML库进行解析操作时,可能会遇到类似于module'yaml'hasnoattribute'FullLoader'的错误。这个错误通常是由于不同版本的PyYAML库之间的差异导致的。在本篇文章中,我们将详细解释这个问题的原因,并提供一些解决方......
  • 【Qt】Qt-文本文件读写
     读取文本文件(编码UTF8)QStringfilename="";QFilefile(filename);if(!file.open(QIODevice::Text|QIODevice::ReadOnly)){  log("Openfilefailed!");  return;}QTextStreamin(&file);in.setCodec("UTF-8");QStringline=in.re......
  • C++ Qt开发:运用QJSON模块解析数据
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QJson组件的实现对JSON文本的灵活解析功能。JSON(JavaScriptObjectNotation)是一种轻量级......