Qt:让任意线程执行一个匿名函数
2015-11-20 19:26
344 查看
本类主要功能是在当前线程(比如说主线程),指派任意一个线程(比如说某个工作线程)去执行一个匿名函数。
注意,这个和QtConcurrent配合QThreadPool不一样,QtConcurrent配合QThreadPool只能指派回调到QThreadPool中的线程。
而这个类可以指派一个回调到任意线程。
两个主要接口
JasonQt_InvokeFromThread::invoke:非阻塞,只是将回调放到队列中,等待执行
JasonQt_InvokeFromThread::waitForInvoke:阻塞,函数执行完成后才回返回
代码部分:
.h文件内容:
.cpp文件内容
测试代码:
执行输出
可以看见,回调被执行在了测试线程中。
注:目标线程需要有运行Qt的事件循环,这是必须的。
注意,这个和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的事件循环,这是必须的。
相关文章推荐
- QT的文件对话框
- Qt 深入介绍信号和槽
- Qt 创建对话框
- QT中的各种MessageBox
- QT程序图标和窗口图标
- QT.Debug设置断点无效
- qt QSharedMemory 用法
- qt 打印信息显示行号
- Qt moc 功能和限制
- Qt之右键菜单实现
- QT创建透明窗体
- Qt Creator快捷键
- Qt Creator快捷键
- Ⅰ.2.9.如何测试支持国际化的Qt AUT
- 使用VS开发Qt项目时编译速度慢的问题解决
- Qt共享内存实现进程间通信(QSharedMemory)
- QTP自动化测试之VBScript对象
- QTP自动化测试之VBScript基础(下)
- QTP自动化测试之VBScript基础(上)
- Qt 实现excel加法