素数计数器

演示如何监控并发操作进度。

以下示例演示了如何使用QFutureWatcher类和filteredReduced函数从Qt Concurrent创建一个交互式且非阻塞的QtWidgets应用程序。使用此示例,用户可以创建一个QList整数列表,它可进行调整大小。列表将自动填充从1开始的连续自然数,直到n。然后程序将在列表中检查素数,并显示找到的素数总数。

运行示例

要从Qt Creator运行示例,请打开欢迎模式,然后从示例中选择示例。有关更多信息,请参阅构建和运行示例

设置连接

Qt Concurrent库提供了filteredReduced函数,它们可以在两种模式中操作:`OrderedReduce`(有序减少)和`UnorderedReduce`(无序减少)。在`OrderedReduce`模式下,减少函数按原始序列的顺序调用,而在`UnorderedReduce`模式下,随机访问元素。

在配置完带有所需元素的UI后,需要使用Qt的信号 & 槽机制将它们连接到并发操作的信号。在此示例中,我们使用QFutureWatcher类来监控并发操作的进度并提供实现交互式GUI所需的信号。

    ...
connect(ui->pushButton, &QPushButton::clicked,
        this, [this] { start(); });
connect(&watcher, &QFutureWatcher<Element>::finished,
        this, [this] { finish(); });
connect(&watcher, &QFutureWatcher<Element>::progressRangeChanged,
        ui->progressBar, &QProgressBar::setRange);
connect(&watcher, &QFutureWatcher<Element>::progressValueChanged,
        ui->progressBar, &QProgressBar::setValue);
    ...

QFutureWatcher类在此示例中发挥着至关重要的作用,因为它提供了更新UI所需的信号,以响应并发操作中的变化。

启动并发操作

连接所有信号 & 槽后,当用户按下QPushButton时,将调用start()函数。

start()函数中,我们从Qt Concurrent调用filteredReduced函数并将未来设置在QFutureWatcher成员上。为了确保此操作真正并发运行,我们指定一个单独的QThreadPool作为第一个参数。这种方法还避免了在全球线程池中的任何可能的阻塞。我们传递一个整数QList作为容器,一个静态过滤和减少函数,以及最终的ReduceOption标志。

    ...
void PrimeCounter::start()
{
    if (ui->pushButton->isChecked()) {
        ui->comboBox->setEnabled(false);
        ui->pushButton->setText(tr("Cancel"));
        ui->labelResult->setText(tr("Calculating ..."));
        ui->labelFilter->setText(tr("Selected Reduce Option: %1").arg(ui->comboBox->currentText()));
        fillElementList(ui->horizontalSlider->value() * stepSize);

        timer.start();
        watcher.setFuture(
            QtConcurrent::filteredReduced(
                &pool,
                elementList,
                filterFunction,
                reduceFunction,
                currentReduceOpt | QtConcurrent::SequentialReduce));
    ...

让我们来检查过滤和归约函数。在这个例子中,这些函数被声明为静态的,因为它们不依赖于任何成员变量。但是,它们也可以很容易地指定为lambda函数或成员函数。

过滤函数用归约函数标记元素。这个实现是一个简单的素数过滤函数。由于这个函数以const引用作为参数,它允许对它所操作的容器进行线程安全的操作。

    ...
bool PrimeCounter::filterFunction(const Element &element)
{
    // Filter for primes
    if (element <= 1)
        return false;
    for (Element i = 2; i*i <= element; ++i) {
        if (element % i == 0)
            return false;
    }
    return true;
}
    ...

归约函数接受与其操作的容器相同类型的可修改引用作为其第一个参数。第二个参数是来自过滤函数的先前过滤元素。在本例中,我们计数素数的数量。

    ...
void PrimeCounter::reduceFunction(Element &out, const Element &value)
{
    // Count the amount of primes.
    Q_UNUSED(value);
    ++out;
}
    ...

示例项目 @ code.qt.io

© 2024 The Qt Company Ltd. 本文档中包含的贡献是各自所有者的版权。本提供的文档是根据自由软件基金会发布的条款在 GNU自由文档许可证1.3版本 下许可的。Qt及其相关标志是芬兰及世界各地的The Qt Company Ltd.的商标。所有其他商标都是其主要所有者的财产。