Qt:让任意线程执行一个匿名函数

来源:互联网 发布:淘宝买家秀 珍珠内裤 编辑:程序博客网 时间:2024/06/14 10:38

本类主要功能是在当前线程(比如说主线程),指派任意一个线程(比如说某个工作线程)去执行一个匿名函数。


注意,这个和QtConcurrent配合QThreadPool不一样,QtConcurrent配合QThreadPool只能指派回调到QThreadPool中的线程。

而这个类可以指派一个回调到任意线程。


两个主要接口

JasonQt_InvokeFromThread::invoke:非阻塞,只是将回调放到队列中,等待执行

JasonQt_InvokeFromThread::waitForInvoke:阻塞,函数执行完成后才回返回


代码部分:


.h文件内容:

#include <QThread>#include <QMap>#include <QDebug>class JasonQt_InvokeFromThreadHelper: public QObject{    Q_OBJECTprivate:    QMutex m_mutex;    QList< std::function<void()> > m_waitCallbacks;public:    void addCallback(const std::function<void()> &callback);public slots:    void onRun();};class JasonQt_InvokeFromThread{private:    static QMutex g_mutex;    static QMap< QThread *, JasonQt_InvokeFromThreadHelper * > g_helpers;public:    static void invoke(QThread *thread, const std::function<void()> &callback);    static void waitForInvoke(QThread *thread, const std::function<void()> &callback);};

.cpp文件内容

// JasonQt_InvokeFromThreadHelpervoid JasonQt_InvokeFromThreadHelper::addCallback(const std::function<void ()> &callback){    m_mutex.lock();    m_waitCallbacks.push_back(callback);    m_mutex.unlock();}void JasonQt_InvokeFromThreadHelper::onRun(){    if(!m_waitCallbacks.isEmpty())    {        m_mutex.lock();        auto callback = m_waitCallbacks.first();        m_waitCallbacks.pop_front();        m_mutex.unlock();        callback();    }}// JasonQt_InvokeFromThreadQMutex JasonQt_InvokeFromThread::g_mutex;QMap< QThread *, JasonQt_InvokeFromThreadHelper * > JasonQt_InvokeFromThread::g_helpers;void JasonQt_InvokeFromThread::invoke(QThread *thread, const std::function<void ()> &callback){    if(!(thread->isRunning()))    {        qDebug() << "JasonQt_InvokeFromThread::invoke: Target thread" << thread << "is not running!";        return;    }    g_mutex.lock();    auto it = g_helpers.find(thread);    if(it == g_helpers.end())    {        auto helper = new JasonQt_InvokeFromThreadHelper;        helper->moveToThread(thread);        QObject::connect(thread, &QThread::finished, [=]()        {            g_mutex.lock();            auto it = g_helpers.find(thread);            if(it != g_helpers.end())            {                g_helpers.erase(it);            }            g_mutex.unlock();        });        g_helpers.insert( thread, helper );        it = g_helpers.find(thread);    }    it.value()->addCallback(callback);    QMetaObject::invokeMethod(it.value(), "onRun", Qt::QueuedConnection);    g_mutex.unlock();}void JasonQt_InvokeFromThread::waitForInvoke(QThread *thread, const std::function<void ()> &callback){    if(!(thread->isRunning()))    {        qDebug() << "JasonQt_InvokeFromThread::waitForInvoke: Target thread" << thread << "is not running!";        return;    }    g_mutex.lock();    auto it = g_helpers.find(thread);    if(it == g_helpers.end())    {        auto helper = new JasonQt_InvokeFromThreadHelper;        helper->moveToThread(thread);        QObject::connect(thread, &QThread::finished, [=]()        {            g_mutex.lock();            auto it = g_helpers.find(thread);            if(it != g_helpers.end())            {                g_helpers.erase(it);            }            g_mutex.unlock();        });        g_helpers.insert( thread, helper );        it = g_helpers.find(thread);    }    it.value()->addCallback([&]()    {        g_mutex.unlock();        callback();    });    QMetaObject::invokeMethod(it.value(), "onRun", Qt::QueuedConnection);    g_mutex.lock();    g_mutex.unlock();}

测试代码:

int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    qDebug() << "Main thread:" << QThread::currentThread();    constexpr auto threadCount = 5;    QVector< QObject * > objects;    QThreadPool threadPool;    objects.resize(threadCount);    threadPool.setMaxThreadCount(threadCount);    for(auto i = 0; i < threadCount; i++)    {        QtConcurrent::run([&objects, i]()        {            objects[i] = new QObject;            qDebug() << "Thread started:" << QThread::currentThread();            QEventLoop().exec();        });    }    // 等待测试线程启动    QThread::sleep(3);    // 调用    for(auto i = 0; i < (threadCount * 2); i++)    {        // 第一个参数是目标线程,第二个是回调        JasonQt_InvokeFromThread::invoke(objects[i % threadCount]->thread(), [=]()        {            qDebug() << "Current thread:" << QThread::currentThread() << ", Flag:" << i;        });    }    return a.exec();}

执行输出

Main thread: QThread(0x7f821951bf30)Thread started: QThread(0x7f8219705ac0, name = "Thread (pooled)")Thread started: QThread(0x7f8219705f90, name = "Thread (pooled)")Thread started: QThread(0x7f82197055f0, name = "Thread (pooled)")Thread started: QThread(0x7f8219705120, name = "Thread (pooled)")Thread started: QThread(0x7f8219704950, name = "Thread (pooled)")Current thread: QThread(0x7f8219704950, name = "Thread (pooled)") , Flag: 0Current thread: QThread(0x7f8219705ac0, name = "Thread (pooled)") , Flag: 3Current thread: QThread(0x7f8219705120, name = "Thread (pooled)") , Flag: 1Current thread: QThread(0x7f82197055f0, name = "Thread (pooled)") , Flag: 2Current thread: QThread(0x7f8219705f90, name = "Thread (pooled)") , Flag: 4Current thread: QThread(0x7f8219704950, name = "Thread (pooled)") , Flag: 5Current thread: QThread(0x7f8219705ac0, name = "Thread (pooled)") , Flag: 8Current thread: QThread(0x7f8219705120, name = "Thread (pooled)") , Flag: 6Current thread: QThread(0x7f8219705f90, name = "Thread (pooled)") , Flag: 9Current thread: QThread(0x7f82197055f0, name = "Thread (pooled)") , Flag: 7

可以看见,回调被执行在了测试线程中。


注:目标线程需要有运行Qt的事件循环,这是必须的。



0 0
原创粉丝点击