让任意线程执行一个匿名函数
Posted 朝闻道
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了让任意线程执行一个匿名函数相关的知识,希望对你有一定的参考价值。
本类主要功能是在当前线程(比如说主线程),指派任意一个线程(比如说某个工作线程)去执行一个匿名函数。
注意,这个和QtConcurrent配合QThreadPool不一样,QtConcurrent配合QThreadPool只能指派回调到QThreadPool中的线程。
而这个类可以指派一个回调到任意线程。
两个主要接口
JasonQt_InvokeFromThread::invoke:非阻塞,只是将回调放到队列中,等待执行
JasonQt_InvokeFromThread::waitForInvoke:阻塞,函数执行完成后才回返回
代码部分:
.h文件内容:
- #include <QThread>
- #include <QMap>
- #include <QDebug>
- class JasonQt_InvokeFromThreadHelper: public QObject
- {
- Q_OBJECT
- private:
- 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_InvokeFromThreadHelper
- void 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_InvokeFromThread
- QMutex 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: 0
- Current thread: QThread(0x7f8219705ac0, name = "Thread (pooled)") , Flag: 3
- Current thread: QThread(0x7f8219705120, name = "Thread (pooled)") , Flag: 1
- Current thread: QThread(0x7f82197055f0, name = "Thread (pooled)") , Flag: 2
- Current thread: QThread(0x7f8219705f90, name = "Thread (pooled)") , Flag: 4
- Current thread: QThread(0x7f8219704950, name = "Thread (pooled)") , Flag: 5
- Current thread: QThread(0x7f8219705ac0, name = "Thread (pooled)") , Flag: 8
- Current thread: QThread(0x7f8219705120, name = "Thread (pooled)") , Flag: 6
- Current thread: QThread(0x7f8219705f90, name = "Thread (pooled)") , Flag: 9
- Current thread: QThread(0x7f82197055f0, name = "Thread (pooled)") , Flag: 7
可以看见,回调被执行在了测试线程中。
注:目标线程需要有运行Qt的事件循环,这是必须的。
http://blog.csdn.net/wsj18808050/article/details/49950871
以上是关于让任意线程执行一个匿名函数的主要内容,如果未能解决你的问题,请参考以下文章