让任意线程执行一个匿名函数
2016-03-31 18:10
337 查看
本类主要功能是在当前线程(比如说主线程),指派任意一个线程(比如说某个工作线程)去执行一个匿名函数。
注意,这个和QtConcurrent配合QThreadPool不一样,QtConcurrent配合QThreadPool只能指派回调到QThreadPool中的线程。
而这个类可以指派一个回调到任意线程。
两个主要接口
JasonQt_InvokeFromThread::invoke:非阻塞,只是将回调放到队列中,等待执行
JasonQt_InvokeFromThread::waitForInvoke:阻塞,函数执行完成后才回返回
代码部分:
.h文件内容:
[cpp] view plain copy
#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文件内容
[cpp] view plain copy
// 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();
}
测试代码:
[cpp] view plain copy
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();
}
执行输出
[cpp] view plain copy
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
注意,这个和QtConcurrent配合QThreadPool不一样,QtConcurrent配合QThreadPool只能指派回调到QThreadPool中的线程。
而这个类可以指派一个回调到任意线程。
两个主要接口
JasonQt_InvokeFromThread::invoke:非阻塞,只是将回调放到队列中,等待执行
JasonQt_InvokeFromThread::waitForInvoke:阻塞,函数执行完成后才回返回
代码部分:
.h文件内容:
[cpp] view plain copy
#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文件内容
[cpp] view plain copy
// 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();
}
测试代码:
[cpp] view plain copy
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();
}
执行输出
[cpp] view plain copy
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
相关文章推荐
- 修改ibdata1大小的验证以及如何使用mysqld_multi管理多实例
- 执行环境和作用域链
- 学习汤姆大叔的knockout教程笔记(一)
- #调整随机森林的参数(调整max_features,结果未见明显差异)
- 按照指定的宽高(或指定比例)来重新设置bitmap
- java程序猿应该了解的10个面向对象设计原则(每次看都很有感悟,特意拿来和大家共享)
- Zmq中pub和sub的用法
- 观察者模式(java)浅析
- ios保存录制好的视频到相簿的方法
- Android初学习 - 基础&进阶总结
- miniGUI3.0.12移植到Hi3531
- Leetcode闲逛随笔
- MySQL 用户执行存储过程的权限
- vs2008+Qt 编译MySQL驱动
- 数据库性能优化
- ajaxFileUpload上传文件没反应
- Mysql 学习笔记
- bean中集合属性的配置
- 夺命雷公狗---DEDECMS----29dedecms热门大片的完成
- cvc-complex-type.2.4.c: 通配符的匹配很全面, 但无法找到元素 'dubbo:application