精华内容
下载资源
问答
  • 先说在线程中使用信号和槽的一些问题1.1 connect的第五个参数[参考]Qt::DirectConnection When emitted, the signal is immediately delivered to the slot. 假设当前有4个slot连接到QPushButton::clicked(bool),当...

    一点一点的记录吧.

    1.先说在线程中使用信号和槽的一些问题

    1.1 connect的第五个参数[参考]

    Qt::DirectConnection When emitted, the signal is immediately delivered to the slot. 假设当前有4个slot连接到QPushButton::clicked(bool),当按钮被按下时,QT就把这4个slot按连接的时间顺序调用一遍。显然这种方式不能跨线程(传递消息)。独立线程内的信号和槽连接方式,比如tcp/ip中的soket连接.

    Qt::QueuedConnection When emitted, the signal is queued until the event loop is able to deliver it to the slot. 假设当前有4个slot连接到QPushButton::clicked(bool),当按钮被按下时,QT就把这个signal包装成一个 QEvent,放到消息队列里。QApplication::exec()或者线程的QThread::exec()会从消息队列里取消息,然后调用 signal关联的几个slot。这种方式既可以在线程内传递消息,也可以跨线程传递消息。

    Qt::BlockingQueuedConnection Same as QueuedConnection, except that the current thread blocks until the slot has been delivered. This connection type should only be used for receivers in a different thread. Note that misuse of this type can lead to dead locks in your application. 与Qt::QueuedConnection类似,但是会阻塞等到关联的slot都被执行。这里出现了阻塞这个词,说明它是专门用来多线程间传递消息的。实现异步处理.

    Qt::AutoConnection If the signal is emitted from the thread in which the receiving object lives, the slot is invoked directly, as with Qt::DirectConnection; otherwise the signal is queued, as with Qt::QueuedConnection. 这种连接类型根据signal和slot是否在同一个线程里自动选择Qt::DirectConnection或Qt::QueuedConnection, 这种方式是默认的连接方式.

    emit 只有在run()里面才会是当作独立线程执行, 因为本质上SIGNAL和SLOT都是一个对象指针.

    2.提升数据库的插入速度

    解决方法:批处理+事务. 参考

    SqlError addMessgeBatch( cosnt QVariantList& msgs)
    {
        QSqlDatabase db = QSqlDatabase::database();
        db.transaction();//开启 事务
    
        QSqlQuery q(db);
        //[0]!批处理
        q.prepare("INSERT INTO Tab_CANMessage VALUES (?,?,?)");
        q.addBindValue(msgs);
    
        if (!q.execBatch()){
            qDebug() << q.lastError();
            return q.lastError();
        //[0]!批处理
        }else{
            db.commit();//提交
        }
        return QSqlError();
    }

    实测:5000条数据(20个字节的char*), 100ms左右.已经满足现在需求.

    展开全文
  • Qt主要提供了如下线程相关的类: 1.QThread:低级别的API(开启事件循环) QThread是Qt中所有线程控制的基础,每个线程实例代表一个线程。有如下两种实现方式: 直接实例化:实例化的线程开启事件循环,允许...

    Qt主要提供了如下线程相关的类:

    1.QThread:低级别的API(开启事件循环)

    QThread是Qt中所有线程控制的基础,每个线程实例代表一个线程。有如下两种实现方式:

    1. 直接实例化:实例化的线程开启事件循环,允许QObject的槽函数在另外的线程中被调用。
    2. 间接子类化:在启动事件循环前,初始化线程;或者不开启事件循环,直接运行代码。

    2.QThreadPool和QRunnable:可复用的线程

    为了避免频繁创建和析构线程所带来的性能损耗,QTheadPool提供一种可线程复用的线程池。

    线程池使用步骤:

    1. 子类化QRunnable;
    2. 重新实现QRunnable的run函数;
    3. 调用QThreadPool::start把QRunnable子类放入到队列中;
    4. 线程可用时,QRunnable::run中的代码会在该线程中运行。

    线程池实例的获取:

    1. 每个Qt程序中默认有全局的线程池,通过QThreadPool::globalInstance()获取。它会根据CPU核数自动的分配线程的数量
    2. 自主创建并管理QThreadPool对象

    代码实例:

    #include <QRunnable>
    #include <QThread>
    #include <QDebug>
    #include <QThreadPool>
    
    class HelloWorldTask : public QRunnable
    {
    	void run()
    	{
    		qDebug() << "Hello world from thread: " << QThread::currentThread();
    	}
    };
    
    void testThreadPoolDemo()
    {
    	qDebug() << "testThreadPoolDemo...";
    	qDebug() << "main thread: " << QThread::currentThread();
     	HelloWorldTask *hello = new HelloWorldTask();
    	// 线程池会自动删除hello
    	QThreadPool::globalInstance()->start(hello);
    };
    

    执行结果:

    testThreadPoolDemo...
    main thread:  QThread(0x717498)
    Hello world from thread:  QThread(0x7409e8, name = "Thread (pooled)")
    

    3.QtConcurrent:高级别的API

    Qt Concurrent提供了高级的方式来处理一些常见的并行计算模式:map(映射)、filter(过滤)、reduce(简化)。不同于QThread和QRunnable,它不会使用低级别的线程原语,如互斥量、信号量等。

    Qt Concurrent的map(映射)、filter(过滤)、reduce(简化)算法可自动的将计算分发到可用的处理器中。主要有如下核心类(函数):

    1. QFuture:获取函数的执行结果,查询计算过程,暂停/恢复/取消计算。
    2. QFutureWatcher:使用信号槽机制与QFuture交互。
    3. QtConcurrent::run():在另外一个线程中执行函数。只能在一个线程中执行,不能查询计算过程,不能暂停/恢复/取消计算。

    代码示例,统计文件的单词:

    #include <QList>
    #include <QMap>
    #include <QTextStream>
    #include <QString>
    #include <QStringList>
    #include <QDir>
    #include <QTime>
    #include <QApplication>
    #include <QDebug>
    
    #include <qtconcurrentmap.h>
    
    using namespace QtConcurrent;
    
    //递归搜索文件
    QStringList findFiles(const QString &startDir, QStringList filters)
    {
        QStringList names;
        QDir dir(startDir);
    
        foreach (QString file, dir.entryList(filters, QDir::Files))
            names += startDir + '/' + file;
    
        foreach (QString subdir, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot))
            names += findFiles(startDir + '/' + subdir, filters);
        return names;
    }
    
    typedef QMap<QString, int> WordCount;
    
    //单线程检索单词
    WordCount singleThreadedWordCount(QStringList files)
    {
        WordCount wordCount;
        foreach (QString file, files) {
            QFile f(file);
            f.open(QIODevice::ReadOnly);
            QTextStream textStream(&f);
            while (textStream.atEnd() == false)
                foreach (const QString &word, textStream.readLine().split(' '))
                    wordCount[word] += 1;
    
        }
        return wordCount;
    }
    
    
    //统计一个文件内的单词数量。该函数被多个线程调用,一定是线程安全的!
    WordCount countWords(const QString &file)
    {
        QFile f(file);
        f.open(QIODevice::ReadOnly);
        QTextStream textStream(&f);
        WordCount wordCount;
    
        while (textStream.atEnd() == false)
            foreach (const QString &word, textStream.readLine().split(' '))
                wordCount[word] += 1;
    
        return wordCount;
    }
    
    //归纳所有的映射结果到最总结过。该函数只被一个线程调用一次!
    void reduce(WordCount &result, const WordCount &w)
    {
        QMapIterator<QString, int> i(w);
        while (i.hasNext()) {
            i.next();
            result[i.key()] += i.value();
        }
    }
    
    int main(int argc, char** argv)
    {
        QApplication app(argc, argv);
        qDebug() << "finding files...";
        QStringList files = findFiles("../../", QStringList() << "*.cpp" << "*.h");
        qDebug() << files.count() << "files";
    
        qDebug() << "warmup";
        {
            QTime time;
            time.start();
            WordCount total = singleThreadedWordCount(files);
        }
    
        qDebug() << "warmup done";
    
        int singleThreadTime = 0;
        {
            QTime time;
            time.start();
            WordCount total = singleThreadedWordCount(files);
            singleThreadTime = time.elapsed();
            qDebug() << "single thread" << singleThreadTime;
        }
    
        int mapReduceTime = 0;
        {
            QTime time;
            time.start();
            WordCount total = mappedReduced(files, countWords, reduce);
            mapReduceTime = time.elapsed();
            qDebug() << "MapReduce" << mapReduceTime;
        }
        qDebug() << "MapReduce speedup x" << ((double)singleThreadTime - (double)mapReduceTime) / (double)mapReduceTime + 1;
    }
    
    

    如何选择?

    如何选择线程实现方式跟线程的使用目的及线程的生命周期有关系。下面给了各种线程实现的对比及使用案例;

    1.方案对比

    特性 QThread QThreadPool QtConcurrent::run Qt Concurrent (Map, Filter, Reduce)
    实现语言 C++ C++ C++ C++
    指定线程优先级
    内部可运行事件循环
    通过信号槽更新数据
    通过信号槽控制线程
    通过QFuture监控线程 部分
    内置暂停/取消/恢复

    2.使用案例

    线程生命周期 操作 方案
    调用一次 在另外一个线程中执行函数,并更新进度数据 1.重新实现QThread::run,启动QThread,发送信号更新进度条;
    2.重新实现QRunnable::run,添加到线程池QThreadPool,更新进度条;
    3.QtConcurrent::run执行函数,更新进度条;
    调用一次 在另外一个线程中执行函数,并获取执行结果 1.QtConcurrent::run执行函数;
    2.函数执行后,使用QFutureWatcher发送结束信号;
    3.使用QFutureWatcher::result获取执行结果
    调用一次 使用所有可用处理器,对用容器中的每一项执行操作 1.使用QtConcurrent::filter选择容器中的元素;
    2.使用QtConcurrent::map对每个元素操作;
    3.使用QtConcurrent::filteredReduced()/QtConcurrent::mappedReduced()将结果汇总
    永久的 在一个线程中根据请求或者数据的不同,执行不同的任务 1.子类化QObject创建一个工作单元;
    2.实例化工作单元并且创建QThread,讲工作单元移入到QThread中;
    3.通过信号槽与工作单元发送数据/命令
    永久的 在线程中重复执行耗时操作,线程无需接受外部信号或事件 1.重新实现QThread::run,执行while循环;
    2.启动线程;
    3.通过信号槽向GUI线程发送数据
    展开全文
  • Qt线程并行翻译

    2020-11-26 15:21:39
        QtConcurrent包括用于并行列表处理的功能性编程样式API,包括用于共享内存(非分布式)系统的MapReduce和FilterReduce实现,以及用于在GUI应用程序中管理异步计算的类: Concurrent Map and Map-Reduce ...

    说明

        用QtConcurrent编写的程序会根据可用的处理器内核数自动调整使用的线程数。
        QtConcurrent包括用于并行列表处理的功能性编程样式API,包括用于共享内存(非分布式)系统的MapReduce和FilterReduce实现,以及用于在GUI应用程序中管理异步计算的类:

    • Concurrent Map and Map-Reduce
    1. QtConcurrent :: map()将函数应用于容器中的每个项目,就地修改这些项目。
    2. QtConcurrent :: mapped()类似于map(),不同之处在于它返回带有修改的新容器。
    3. QtConcurrent :: mappedReduced()类似于mapping(),不同之处在于修改后的结果被缩减或折叠为单个结果。
    • Concurrent Filter and Filter-Reduce
    1. QtConcurrent :: filter()根据过滤器功能的结果从容器中删除所有项目。
    2. QtConcurrent :: filtered()类似于filter(),不同之处在于它返回带有过滤结果的新容器。
    3. QtConcurrent :: filteredReduced()类似于filtered(),不同之处在于将过滤后的结果减少或折叠成单个结果。
    • Concurrent Run
      QtConcurrent :: run()在另一个线程中运行一个函数。
    • QFuture表示异步计算的结果。
    • QFutureIterator允许迭代通过QFuture可获得的结果。
    • QFutureWatcher允许使用信号和插槽监视QFuture。
    • QFutureSynchronizer是一个便利类,可自动同步多个QFuture。
    • Qt Concurrent支持几种与STL兼容的容器和迭代器类型,但最适合具有随机访问迭代器的Qt容器,例如QList或QVector。映射和过滤器函数接受容器和开始/结束迭代器。

        Qt Concurrent支持几种与STL兼容的容器和迭代器类型,但最适合具有随机访问迭代器的Qt容器,例如QList或QVector。映射和过滤器函数接受容器和开始/结束迭代器。

    STL迭代器支持概述:

    迭代器类型 示例类 支持状态
    输入迭代器 不支持
    输出迭代器 不支持
    正向迭代器 std::slist 支持的
    双向迭代器 QLinkedList,std ::list 支持的
    随机访问迭代器 QList,QVector,std ::vector 支持和推荐

        在Qt Concurrent迭代大量轻量级项目的情况下,随机访问迭代器会更快,因为它们允许跳转到容器中的任何点。另外,使用随机访问迭代器允许Qt Concurrent通过QFuture :: progressValue()和QFutureWatcher ::progressValueChanged()提供进度信息。
        调用时,非原位修改函数(例如,mapped()和filtered())会复制容器。如果您使用的是STL容器,则此复制操作可能会花费一些时间,在这种情况下,我们建议改为指定容器的开始和结束迭代器。

    Concurrent Map and Map-Reduce

        QtConcurrent::map(),QtConcurrent::mapped()和QtConcurrent::mappedReduced()函数对诸如QList或QVector之类的项目并行运行计算。QtConcurrent::map()修改一个序列,QtConcurrent::mapped()返回一个包含修改内容的新序列,而QtConcurrent::mappedReduced()返回一个结果。
        这些功能是Qt Concurrent框架的一部分。
        上述每个函数都有一个阻塞变量,该变量返回最终结果而不是QFuture。您以与异步变量相同的方式使用它们。

    QList<QImage> images = ...;
    // 每个调用都会阻塞,直到整个操作完成为止。
    QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);
    QtConcurrent::blockingMap(images, scale);
    QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);
    

        请注意,上面的结果类型不是QFuture对象,而是实际的结果类型(在这种情况下,为QList 和QImage)

    Concurrent Map

        QtConcurrent::mapped()接受输入序列和映射函数。然后,为序列中的每个项目调用此map函数,并返回一个新序列,其中包含map函数的返回值。
        map函数必须采用以下形式:

    U function(const T &t);
    

        T和U可以是任何类型(甚至可以是同一类型),但是T必须与序列中存储的类型匹配。该函数返回修改或映射的内容。
        本示例说明如何将缩放功能应用于序列中的所有项目:

    QImage scaled(const QImage &image){return image.scaled(100, 100);}
    QList<QImage> images = ...;
    QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);
    

        mapped的结果可通过QFuture获得。
        如果要就地修改序列,请使用QtConcurrent::map()。然后,map函数必须采用以下形式:

    U function(T &t);
    

        请注意,未使用map函数的返回值和返回类型。
        使用QtConcurrent::map()类似于使用QtConcurrent::mapped():

    void scale(QImage &image){image = image.scaled(100, 100);}
    QList<QImage> images = ...;
    QFuture<void> future = QtConcurrent::map(images, scale);
    

        由于已在适当位置修改了序列,因此QtConcurrent::map()不会通过QFuture返回任何结果。但是,您仍然可以使用QFuture和QFutureWatcher监视地图的状态。

    Concurrent Map-Reduce

        QtConcurrent::mappedReduced()与QtConcurrent::mapped()相似,但不是使用新的结果返回序列,而是使用reduce函数将结果合并为一个值。
        reduce函数的形式必须为:

    V function(T &result, const U &intermediate)
    

        T是最终结果的类型,U是映射函数的返回类型。请注意,未使用reduce函数的返回值和返回类型。
        像这样调用QtConcurrent::mappedReduced():

    void addToCollage(QImage &collage, const QImage &thumbnail)
    {
        QPainter p(&collage);
        static QPoint offset = QPoint(0, 0);
        p.drawImage(offset, thumbnail);
        offset += ...;
    }
    QList<QImage> images = ...;
    QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled, addToCollage);
    

        对于map函数返回的每个结果,reduce函数将被调用一次,并且应将中间函数合并到result变量中。QtConcurrent::mappedReduced()保证一次仅一个线程将调用reduce,因此不需要使用互斥锁来锁定结果变量。该QtConcurrent::ReduceOptions枚举提供了一种方法来控制它的降低完成的顺序。如果使用QtConcurrent::UnorderedReduce(默认设置),则顺序是未定义的,而QtConcurrent::OrderedReduce可确保按原始序列的顺序进行缩小。

    其他API功能

    使用迭代器代替序列

        上面的每个函数都有一个采用迭代器范围而不是序列的变量。您以与序列变体相同的方式使用它们:

    QList<QImage> images = ...;
    QFuture<QImage> thumbnails = QtConcurrent::mapped(images.constBegin(), images.constEnd(), scaled);
    // 就地映射仅适用于非常量迭代器。
    QFuture<void> future = QtConcurrent::map(images.begin(), images.end(), scale);
    QFuture<QImage> collage = QtConcurrent::mappedReduced(images.constBegin(), images.constEnd(), scaled, addToCollage);
    

    拥塞Variants

        上述每个函数都有一个阻塞变量,该变量返回最终结果而不是QFuture。您以与异步变量相同的方式使用它们。

    QList<QImage> images = ...;
    // 每个调用都会阻塞,直到整个操作完成
    QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);
    QtConcurrent::blockingMap(images, scale);
    QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);
    

        请注意,上面的结果类型不是QFuture对象,而是实际的结果类型(在这种情况下,为QList 和QImage)。

    使用成员函数

        QtConcurrent::map(),QtConcurrent::mapped()和QtConcurrent::mappedReduced()接受指向成员函数的指针。成员函数类的类型必须与序列中存储的类型匹配:

    // 压缩QStringList中的所有字符串。
    QStringList strings = ...;
    QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze);
    // 交换图像列表中所有像素的rgb值。
    QList<QImage> images = ...;
    QFuture<QImage> bgrImages = QtConcurrent::mapped(images, &QImage::rgbSwapped);
    // 在列表中创建一组所有字符串的长度。
    QStringList strings = ...;
    QFuture<QSet<int> > wordLengths = QtConcurrent::mappedReduced(strings, &QString::length, &QSet<int>::insert);
    

        请注意,使用QtConcurrent::mappedReduced()时,您可以自由地混合使用普通函数和成员函数:

    // 可以将普通函数和成员函数与QtConcurrent::mappedReduced()混合使用。
    // 计算一个字符串列表的平均长度。
    extern void computeAverage(int &average, int length);
    QStringList strings = ...;
    QFuture<int> averageWordLength = QtConcurrent::mappedReduced(strings, &QString::length, computeAverage);
    
    // 为列表中的所有图像创建一组颜色分布。
    extern int colorDistribution(const QImage &string);
    QList<QImage> images = ...;
    QFuture<QSet<int> > totalColorDistribution = QtConcurrent::mappedReduced(images, colorDistribution, QSet<int>::insert);
    
    使用函数对象

        QtConcurrent::map(),QtConcurrent::mapped()和QtConcurrent::mappedReduced()接受map函数的函数对象。这些函数对象可用于将状态添加到函数调用中。result_type typedef必须定义函数调用运算符的结果类型:

    struct Scaled
    {
        Scaled(int size)
        : m_size(size) { }
    
        typedef QImage result_type;
    
        QImage operator()(const QImage &image)
        {
            return image.scaled(m_size, m_size);
        }
    
        int m_size;
    };
    
    QList<QImage> images = ...;
    QFuture<QImage> thumbnails = QtConcurrent::mapped(images, Scaled(100));
    

        对于reduce函数,不直接支持函数对象。但是,当明确指定归约结果的类型时,可以使用函数对象:

    struct ImageTransform
    {
        void operator()(QImage &result, const QImage &value);
    };
    
    QFuture<QImage> thumbNails =
      QtConcurrent::mappedReduced<QImage>(images,
                                          Scaled(100),
                                          ImageTransform(),
                                          QtConcurrent::SequentialReduce);
    
    使用多个参数封装函数

        如果要使用带有多个参数的map函数,则可以使用lambda函数或std::bind()将其转换为带有一个参数的函数。
    例如,我们将使用QImage::scaledToWidth():

    QImage QImage::scaledToWidth(int width, Qt::TransformationMode) const;
    

        scaledToWidth具有三个参数(包括“ this”指针),不能直接与QtConcurrent::mapped()一起使用,因为QtConcurrent::mapped()期望一个带有一个参数的函数。要将QImage::scaledToWidth()与QtConcurrent::mapped()结合使用,我们必须提供宽度值和转换模式的值:

    QList<QImage> images = ...;
    std::function<QImage(const QImage &)> scale = [](const QImage &img) {
        return img.scaledToWidth(100, Qt::SmoothTransformation);
    };
    QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scale);
    

    Concurrent Filter and Filter-Reduce

        QtConcurrent::filter(),QtConcurrent::filtered()和QtConcurrent::filteredReduced()函数可按顺序过滤诸如QList或QVector之类的项。QtConcurrent::filter()修改一个序列,QtConcurrent::filtered()返回一个包含过滤内容的新序列,而QtConcurrent::filteredReduced()返回一个结果。
        这些功能是Qt Concurrent框架的一部分。
        以上每个函数都有一个阻塞变量,该变量返回最终结果而不是QFuture。您以与异步变量相同的方式使用它们。

    QStringList strings = ...;
    // 每个调用都会阻塞,直到整个操作完成为止
    QStringList lowerCaseStrings = QtConcurrent::blockingFiltered(strings, allLowerCase);
    QtConcurrent::blockingFilter(strings, allLowerCase);
    QSet<QString> dictionary = QtConcurrent::blockingFilteredReduced(strings, allLowerCase, addToDictionary);
    

        请注意,上面的结果类型不是QFuture对象,而是实际的结果类型(在这种情况下,为QStringList和QSet <)。

    Concurrent Filter

        QtConcurrent::filtered()接受输入序列和过滤器函数。然后,为序列中的每个项目调用此过滤器函数,并返回包含过滤后值的新序列。
        过滤器函数的形式必须为:

    bool function(const T &t);
    

    T必须与序列中存储的类型匹配。true如果应保留该项目,则函数返回;如果应丢弃,则返回false。
    此示例显示如何从QStringList保留所有小写的字符串:

    bool allLowerCase(const QString &string)
    {
        return string.lowered() == string;
    }
    QStringList strings = ...;
    QFuture<QString> lowerCaseStrings = QtConcurrent::filtered(strings, allLowerCase);
    

    过滤器的结果可通过QFuture获得。
    如果要就地修改序列,请使用QtConcurrent::filter():

    QStringList strings = ...;
    QFuture<void> future = QtConcurrent::filter(strings, allLowerCase);
    

    由于已在适当位置修改了序列,因此QtConcurrent::filter()不会通过QFuture返回任何结果。但是,您仍然可以使用QFuture和QFutureWatcher监视过滤器的状态。

    Concurrent Filter-Reduce

    QtConcurrent::filteredReduced()与QtConcurrent::filtered()相似,但不是使用已过滤的结果重新播放序列,而是使用reduce函数将结果合并为单个值。
    reduce函数的形式必须为:

    V function(T &result, const U &intermediate)
    

    T是最终结果的类型,U是要过滤的项目的类型。请注意,未使用reduce函数的返回值和返回类型。
    像这样调用QtConcurrent::filteredReduced():

    void addToDictionary(QSet<QString> &dictionary, const QString &string)
    {
        dictionary.insert(string);
    }
    QStringList strings = ...;
    QFuture<QSet<QString> > dictionary = QtConcurrent::filteredReduced(strings, allLowerCase, addToDictionary);
    

    将对filter函数保存的每个结果调用一次reduce函数,并且应将中间函数合并到result变量中。QtConcurrent::filteredReduced()保证一次只有一个线程将调用reduce,因此不需要使用互斥锁来锁定结果变量。该QtConcurrent::ReduceOptions枚举提供了一种方法来控制它的降低完成的顺序。

    其他API功能

    使用迭代器代替序列
    上面的每个函数都有一个采用迭代器范围而不是序列的变量。您以与序列变体相同的方式使用它们:

    QStringList strings = ...;
    QFuture<QString> lowerCaseStrings = QtConcurrent::filtered(strings.constBegin(), strings.constEnd(), allLowerCase);
    // 就地过滤器仅适用于非常量迭代器
    QFuture<void> future = QtConcurrent::filter(strings.begin(), strings.end(), allLowerCase);
    QFuture<QSet<QString> > dictionary = QtConcurrent::filteredReduced(strings.constBegin(), strings.constEnd(), allLowerCase, addToDictionary);
    

    使用成员函数

    QtConcurrent::filter(),QtConcurrent::filtered()和QtConcurrent::filteredReduced()接受指向成员函数的指针。成员函数类的类型必须与序列中存储的类型匹配:

    //仅保留具有Alpha通道
    QList<QImage> images = ...;
    QFuture<void> alphaImages = QtConcurrent::filter(images, &QImage::hasAlphaChannel);
    // 检索灰度图像
    QList<QImage> images = ...;
    QFuture<QImage> grayscaleImages = QtConcurrent::filtered(images, &QImage::isGrayscale);
    //创建一组所有可打印字符
    QList<QChar> characters = ...;
    QFuture<QSet<QChar> > set = QtConcurrent::filteredReduced(characters, &QChar::isPrint, &QSet<QChar>::insert);
    

    请注意,使用QtConcurrent::filteredReduced()时,您可以自由地混合使用普通函数和成员函数:

    // 可以将普通函数和成员函数与QtConcurrent::filteredReduced()混合使用
    
    // 创建所有小写字符串的字典
    extern bool allLowerCase(const QString &string);
    QStringList strings = ...;
    QFuture<QSet<int> > averageWordLength = QtConcurrent::filteredReduced(strings, allLowerCase, QSet<QString>::insert);
    // 创建所有的灰度图像的拼贴
    extern void addToCollage(QImage &collage, const QImage &grayscaleImage);
    QList<QImage> images = ...;
    QFuture<QImage> collage = QtConcurrent::filteredReduced(images, &QImage::isGrayscale, addToCollage);
    

    使用函数对象

    QtConcurrent::filter(),QtConcurrent::filtered()和QtConcurrent::filteredReduced()接受用于过滤器功能的功能对象。这些函数对象可用于将状态添加到函数调用中。result_type typedef必须定义函数调用运算符的结果类型:

    struct StartsWith
    {
        StartsWith(const QString &string)
        : m_string(string) { }
        typedef bool result_type;
        bool operator()(const QString &testString)
        {
            return testString.startsWith(m_string);
        }
        QString m_string;
    };
    
    QList<QString> strings = ...;
    QFuture<QString> fooString = QtConcurrent::filtered(strings, StartsWith(QLatin1String("Foo")));
    

    对于reduce函数,不直接支持函数对象。但是,当明确指定归约结果的类型时,可以使用函数对象:

    struct StringTransform
    {
        void operator()(QString &result, const QString &value);
    };
    QFuture<QString> fooString =
      QtConcurrent::filteredReduced<QString>(strings,
                                             StartsWith(QLatin1String("Foo")),
                                             StringTransform());
    

    封装多个参数的函数

    如果要使用带多个参数的过滤器函数,则可以使用lambda函数或std::bind()将其转换为带一个参数的函数。
    例如,我们使用QString::contains():

    bool QString::contains(const QRegularExpression &regexp) const;
    

    QString::contains()需要2个参数(包括“ this”指针),不能直接与QtConcurrent::filtered()一起使用,因为QtConcurrent::filtered()需要一个带有一个参数的函数。要将QString::contains()与QtConcurrent::filtered()一起使用,我们必须为regexp参数提供一个值:

    QStringList strings = ...;
    QFuture<QString> future = QtConcurrent::filtered(list, [](const QString &str) {
        return str.contains(QRegularExpression("^\\S+$")); // matches strings without whitespace
    });
    

    Concurrent Run

    QtConcurrent::run()函数在单独的线程中运行一个函数。该函数的返回值可通过QFuture API获得。
    此功能是Qt Concurrent框架的一部分。

    在单独的线程中运行函数

    要在另一个线程中运行一个函数,请使用QtConcurrent::run():

    extern void aFunction();
    QFuture<void> future = QtConcurrent::run(aFunction);
    

    这将在从默认QThreadPool获得的单独线程中运行aFunction。您可以使用QFuture和QFutureWatcher类来监视函数的状态。
    要使用专用线程池,可以将QThreadPool作为第一个参数传递:

    extern void aFunction();
    QThreadPool pool;
    QFuture<void> future = QtConcurrent::run(&pool, aFunction);
    

    将参数传递给函数

    通过将参数添加到函数名称后面的QtConcurrent::run()调用中,将参数传递给函数。例如:

    extern void aFunctionWithArguments(int arg1, double arg2, const QString &string);
    int integer = ...;
    double floatingPoint = ...;
    QString string = ...;
    QFuture<void> future = QtConcurrent::run(aFunctionWithArguments, integer, floatingPoint, string);
    

    在调用QtConcurrent::run()的位置创建每个参数的副本,并且在开始执行该函数时,这些值将传递给线程。调用QtConcurrent::run()之后对参数所做的更改对线程不可见。

    从函数返回值

    该函数的任何返回值都可以通过QFuture获得:

    extern QString functionReturningAString();
    QFuture<QString> future = QtConcurrent::run(functionReturningAString);
    ...
    QString result = future.result();
    

    如上文所述,传递参数的方式如下:

    extern QString someFunction(const QByteArray &input);
    QByteArray bytearray = ...;
    QFuture<QString> future = QtConcurrent::run(someFunction, bytearray);
    ...
    QString result = future.result();
    

    请注意,QFuture::result()函数将阻止并等待结果变为可用。当函数完成执行并且结果可用时,使用QFutureWatcher获取通知。

    其他API功能

    使用成员函数

    QtConcurrent::run()也接受指向成员函数的指针。第一个参数必须是const引用或指向类实例的指针。调用const成员函数时,通过const引用传递很有用。通过指针传递对于调用修改实例的非常量成员函数很有用。
    例如,在单独的线程中调用QByteArray::split()(一个const成员函数)是这样完成的:

    //在单独的线程中调用“ QList <QByteArray> QByteArray::split(char sep)const” 
    QByteArray bytearray = "hello world";
    QFuture<QList<QByteArray> > future = QtConcurrent::run(bytearray, &QByteArray::split, ',');
    ...
    QList<QByteArray> result = future.result();
    

    调用非常量成员函数的操作如下:

    //在单独的线程中调用'void QImage :: invertPixels(InvertMode mode)'
    QImage image = ...;
    QFuture<void> future = QtConcurrent::run(&image, &QImage::invertPixels, QImage::InvertRgba);
    ...
    future.waitForFinished();
    //此时,“图像”中的像素已反转
    

    使用Lambda函数

    调用lambda函数是这样完成的:

    QFuture<void> future = QtConcurrent::run([=]() {
        // Code in this block will run in another thread
    });
    ...
    
    展开全文
  • Qt中的线程 Qt提供了平台无关的线程类,提供了一种线程安全的方式发送事件、跨线程的信号槽连接。具有如下优势: 很容易开发跨平台的多线程程序; 充分发挥多核处理器的优势; 在不阻塞界面的情况下,执行耗时操作...

    Qt中的线程

    Qt提供了平台无关的线程类,提供了一种线程安全的方式发送事件、跨线程的信号槽连接。具有如下优势:

    1. 很容易开发跨平台的多线程程序;
    2. 充分发挥多核处理器的优势;
    3. 在不阻塞界面的情况下,执行耗时操作。

    总结主题

    本系列会从如下方面总结:
    1. 线程相关类
    2. Qt中的多线程技术
    3. 线程同步
    4. 可重入和线程安全
    5. 线程和QObjects

    展开全文
  • 计算机操作系统对于并发性和并行性的概念给出的定义是: 并行性是指两个或多个事件在同一时刻发生; 并发性是指两个或多个事件在同一时间段内发生。 所以,在我看来,并行,就是两个人操作两个机器,而并发就是一个...
  • 线程的目的是为了并行的执行代码,有时线程需要互相等待。例如,如果两个线程同时写一个变量,执行结果是未定义的。因此对共享资源的需要进行“同步”处理。Qt提供了低级别的、高级别的机制处理线程同步。 低级别的...
  • QT和MPI结合编程

    热门讨论 2012-10-27 11:04:39
    QT和MPI、结合编程的配置过程。MPI是一个并行消息传递借口,QT用于实现界面编程
  • 查看Qt的帮助文档,经常看到函数标识“可重入”和“线程安全”,这些说明了在多线程程序中是如何使用的: 线程安全:函数可以被多个线程同时调用,甚至是调用方使用共享数据。因为所有对共享数据的引用是序列化的。...
  • 编程问题选择数据结构可能是整个解决方案的关键部分,并行程序也不例外。如果一个数据结构需要被多个线程访问,要么它完全不可变,因此数据永远不会变化,并且没有必要同步,要么程序必须设计成确保变动在线程间被...
  • Qt多线程编程示例--代码基于python

    千次阅读 2018-04-01 01:48:57
    由于今天需要处理1000多个视频的相关工作,以往那种直接new很多个QThread的操作会直接卡死,所以模拟了一个线程池,同时只并行几个任务,余下的任务在队列等候,很像我们平时下载东西时那样子。下面这个示例是我编程...
  • 所有的线程看起来是并行的执行,但是从CPU的角度来看,是CPU调度执行,共享CPU资源,但调度非常快,给我们的主观感受是并行执行。在单CPU资源中,是线程的并行执行,是CPU调度产生的。线程都会死亡的,死亡分为自然...
  • 多线程是实现并行处理的重要手段,在GUI编程中,经常需要将耗费任务分离,用单独的线程来处理,避免对主线程造成影响(最常见的影响就是会造成主界面无法响应的假死现象)。在Qt中,最常用的多线程一般是通过继承...
  • 多线程是实现并行处理的重要手段,在GUI编程中,经常需要将耗费任务分离,用单独的线程来处理,避免对主线程造成影响(最常见的影响就是会造成主界面无法响应的假死现象)。在Qt中,最常用的多线程一般是通过继承...
  • 前言:  开始写这个小程序的起因是项目开发中版本Release后交给工厂进行eMMC数据写入生产时候,事先需要计算一下从eMMC母片中导出的二进制BIN文件的CheckSum,以便与eMMC编程器写入时候计算的CheckSum对比是否一致...
  • QT线程2

    2015-12-31 21:50:29
    介绍 ...快速检阅一下他们的代码,在发现的问题当中,十之八九遇到得最大问题是他们在某个地方使用了线程,而随后又坠入了并行编程的陷阱。Qt中创建、运行线程的“易用”性、缺乏相关编程尤其是异
  • 全文共2036字,预计学习时长6分钟图源:unsplash异步编程是并行编程的一种方式。单个工作单元独立于主应用程序线程运行,并通知调用线程其完成、失败情况或进度。下面这张图理解起来会更直观一些:同步vs异步同步...
  • Qt 之保持 GUI 响应

    万次阅读 多人点赞 2016-07-13 21:13:44
    简述Qter们经常遇到由于耗时操作造成GUI阻塞的问题...并行编程 总结 更多参考执行长时间操作要做的第一件事就是确定问题的区域和能被解决的轮廓路径。上述问题可以采取两种形式之一。第一个变化是当一个程序执行计算密
  • Qt 之 Concurrent 框架

    万次阅读 2016-07-29 16:32:38
    简述 QtConcurrent命名空间提供了一个高级API来编写多线程程序,而无需使用低级线程原语,例如:互斥、读写锁、等待...QtConcurrent为并行列表处理包含了函数式编程风格APIs,包括用于共享内存(非分布式)系统的一
  • Qt线程、事件与QObject

    2014-09-14 11:03:29
    介绍 You’re doing it wrong...快速检阅一下他们的代码,在发现的问题当中,十之八九遇到得最大问题是他们在某个地方使用了线程,而随后又坠入了并行编程的陷阱。Qt中创建、运行线程的“易用”性、缺乏相关编程尤
  • 快速检阅一下他们的代码,在发现的问题当中,十之八九遇到得最大问题是他们在某个地方使用了线程,而随后又坠入了并行编程的陷阱。Qt中创建、运行线程的“易用”性、缺乏相关编程尤其是异步网络编程知识或是养成的...
  • Qt Concurrent Run 简述

    2020-05-26 11:08:58
    QtConcurrent命名空间为了多线程编程提供了更高级的API,使用QtConcurrent时,Qt会根据CPU的核数自动分配线程。然而,当需要与正在运行的线程进行通信时,则不能使用QtConcurrent来实现,并且不应将其用于处理阻塞...
  • Qt之保持GUI响应

    2016-07-13 21:13:00
    简述 Qter们经常遇到由于耗时操作造成GUI阻塞的问题。其实,这个问题并不难克服,可以采用许多不同的方式,下面我会列举一些可选范围,...并行编程 总结 更多参考 执行耗时操作 我们需要做的第一件事就是确...
  • [Qt] 线程,事件和QObject

    千次阅读 2012-04-05 16:03:20
    粗看他们的代码,问题十有八九是第一次使用线程,而他们落入了并行编程的陷阱中了。 对在Qt中创建和运行线程和编程风格的缺失和用其它语言和工具的习惯,经常导致人们搬起石头砸自己的脚。同时,线程支持在Qt中是一...

空空如也

空空如也

1 2 3
收藏数 59
精华内容 23
关键字:

qt并行编程