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

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

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

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

两个主要接口

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

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

代码部分:

.h文件内容:

[cpp] view plain copy

  1. #include <QThread>
  2. #include <QMap>
  3. #include <QDebug>
  4. class JasonQt_InvokeFromThreadHelper: public QObject
  5. {
  6. Q_OBJECT
  7. private:
  8. QMutex m_mutex;
  9. QList< std::function<void()> > m_waitCallbacks;
  10. public:
  11. void addCallback(const std::function<void()> &callback);
  12. public slots:
  13. void onRun();
  14. };
  15. class JasonQt_InvokeFromThread
  16. {
  17. private:
  18. static QMutex g_mutex;
  19. static QMap< QThread *, JasonQt_InvokeFromThreadHelper * > g_helpers;
  20. public:
  21. static void invoke(QThread *thread, const std::function<void()> &callback);
  22. static void waitForInvoke(QThread *thread, const std::function<void()> &callback);
  23. };

.cpp文件内容

[cpp] view plain copy

  1. // JasonQt_InvokeFromThreadHelper
  2. void JasonQt_InvokeFromThreadHelper::addCallback(const std::function<void ()> &callback)
  3. {
  4. m_mutex.lock();
  5. m_waitCallbacks.push_back(callback);
  6. m_mutex.unlock();
  7. }
  8. void JasonQt_InvokeFromThreadHelper::onRun()
  9. {
  10. if(!m_waitCallbacks.isEmpty())
  11. {
  12. m_mutex.lock();
  13. auto callback = m_waitCallbacks.first();
  14. m_waitCallbacks.pop_front();
  15. m_mutex.unlock();
  16. callback();
  17. }
  18. }
  19. // JasonQt_InvokeFromThread
  20. QMutex JasonQt_InvokeFromThread::g_mutex;
  21. QMap< QThread *, JasonQt_InvokeFromThreadHelper * > JasonQt_InvokeFromThread::g_helpers;
  22. void JasonQt_InvokeFromThread::invoke(QThread *thread, const std::function<void ()> &callback)
  23. {
  24. if(!(thread->isRunning()))
  25. {
  26. qDebug() << "JasonQt_InvokeFromThread::invoke: Target thread" << thread << "is not running!";
  27. return;
  28. }
  29. g_mutex.lock();
  30. auto it = g_helpers.find(thread);
  31. if(it == g_helpers.end())
  32. {
  33. auto helper = new JasonQt_InvokeFromThreadHelper;
  34. helper->moveToThread(thread);
  35. QObject::connect(thread, &QThread::finished, [=]()
  36. {
  37. g_mutex.lock();
  38. auto it = g_helpers.find(thread);
  39. if(it != g_helpers.end())
  40. {
  41. g_helpers.erase(it);
  42. }
  43. g_mutex.unlock();
  44. });
  45. g_helpers.insert( thread, helper );
  46. it = g_helpers.find(thread);
  47. }
  48. it.value()->addCallback(callback);
  49. QMetaObject::invokeMethod(it.value(), "onRun", Qt::QueuedConnection);
  50. g_mutex.unlock();
  51. }
  52. void JasonQt_InvokeFromThread::waitForInvoke(QThread *thread, const std::function<void ()> &callback)
  53. {
  54. if(!(thread->isRunning()))
  55. {
  56. qDebug() << "JasonQt_InvokeFromThread::waitForInvoke: Target thread" << thread << "is not running!";
  57. return;
  58. }
  59. g_mutex.lock();
  60. auto it = g_helpers.find(thread);
  61. if(it == g_helpers.end())
  62. {
  63. auto helper = new JasonQt_InvokeFromThreadHelper;
  64. helper->moveToThread(thread);
  65. QObject::connect(thread, &QThread::finished, [=]()
  66. {
  67. g_mutex.lock();
  68. auto it = g_helpers.find(thread);
  69. if(it != g_helpers.end())
  70. {
  71. g_helpers.erase(it);
  72. }
  73. g_mutex.unlock();
  74. });
  75. g_helpers.insert( thread, helper );
  76. it = g_helpers.find(thread);
  77. }
  78. it.value()->addCallback([&]()
  79. {
  80. g_mutex.unlock();
  81. callback();
  82. });
  83. QMetaObject::invokeMethod(it.value(), "onRun", Qt::QueuedConnection);
  84. g_mutex.lock();
  85. g_mutex.unlock();
  86. }

测试代码:

[cpp] view plain copy

  1. int main(int argc, char *argv[])
  2. {
  3. QCoreApplication a(argc, argv);
  4. qDebug() << "Main thread:" << QThread::currentThread();
  5. constexpr auto threadCount = 5;
  6. QVector< QObject * > objects;
  7. QThreadPool threadPool;
  8. objects.resize(threadCount);
  9. threadPool.setMaxThreadCount(threadCount);
  10. for(auto i = 0; i < threadCount; i++)
  11. {
  12. QtConcurrent::run([&objects, i]()
  13. {
  14. objects[i] = new QObject;
  15. qDebug() << "Thread started:" << QThread::currentThread();
  16. QEventLoop().exec();
  17. });
  18. }
  19. // 等待测试线程启动
  20. QThread::sleep(3);
  21. // 调用
  22. for(auto i = 0; i < (threadCount * 2); i++)
  23. {
  24. // 第一个参数是目标线程,第二个是回调
  25. JasonQt_InvokeFromThread::invoke(objects[i % threadCount]->thread(), [=]()
  26. {
  27. qDebug() << "Current thread:" << QThread::currentThread() << ", Flag:" << i;
  28. });
  29. }
  30. return a.exec();
  31. }

执行输出

[cpp] view plain copy

  1. Main thread: QThread(0x7f821951bf30)
  2. Thread started: QThread(0x7f8219705ac0, name = "Thread (pooled)")
  3. Thread started: QThread(0x7f8219705f90, name = "Thread (pooled)")
  4. Thread started: QThread(0x7f82197055f0, name = "Thread (pooled)")
  5. Thread started: QThread(0x7f8219705120, name = "Thread (pooled)")
  6. Thread started: QThread(0x7f8219704950, name = "Thread (pooled)")
  7. Current thread: QThread(0x7f8219704950, name = "Thread (pooled)") , Flag: 0
  8. Current thread: QThread(0x7f8219705ac0, name = "Thread (pooled)") , Flag: 3
  9. Current thread: QThread(0x7f8219705120, name = "Thread (pooled)") , Flag: 1
  10. Current thread: QThread(0x7f82197055f0, name = "Thread (pooled)") , Flag: 2
  11. Current thread: QThread(0x7f8219705f90, name = "Thread (pooled)") , Flag: 4
  12. Current thread: QThread(0x7f8219704950, name = "Thread (pooled)") , Flag: 5
  13. Current thread: QThread(0x7f8219705ac0, name = "Thread (pooled)") , Flag: 8
  14. Current thread: QThread(0x7f8219705120, name = "Thread (pooled)") , Flag: 6
  15. Current thread: QThread(0x7f8219705f90, name = "Thread (pooled)") , Flag: 9
  16. Current thread: QThread(0x7f82197055f0, name = "Thread (pooled)") , Flag: 7

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

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

http://blog.csdn.net/wsj18808050/article/details/49950871

时间: 2024-10-24 18:44:12

让任意线程执行一个匿名函数的相关文章

声明函数 执行上下文 匿名函数

方法一: var foo = function () { //code } 方法二: function foo () { //code } 方法一:foo在进入函数执行上下文开始执行代码的时候,foo是undefined的,执行完var foo = function () { }这句,foo才会得到赋值: 方法二:在进入函数执行上下文开始执行代码的时候,foo已经是一个function了. 一旦进入执行上下文(在执行代码之前),VO(变量对象)就会被一些属性填充: 函数的形参(当进入函数执行上下

立即执行的匿名函数

(function($){ ... })(jQuery)是一个“立即执行的匿名函数”,构成了一个闭包,可以防止命名冲突.在匿名函数内部,$参数引用jQuery对象.这个匿名函数不会等到DOM就绪就会执行.注意,使用这个hack时,脚本必须是在页面的head元素中链接和(或)执行的.之所以选择这个时机,因为这时候刚好document元素可用,而整个DOM还远未生成:如果把脚本放在结束的body标签前面,就没有意义了,因为那时候DOM已经完全可用了. 转自:http://www.cnblogs.co

自执行的匿名函数!function()

最近有空可以让我静下心来看看各种代码,function与感叹号的频繁出现,让我回想起2个月前我回杭州最后参加团队会议的时候,@西子剑影抛出的一样的问题:如果在function之前加上感叹号 (!) 会怎么样?比如下面的代码: !function(){alert('iifksp')}() // true 在控制台运行后得到的值时true,为什么是true这很容易理解,因为这个匿名函数没有返回值,默认返回的就是undefined,求反的结果很自然的就是true.所以问题并不在于结果值,而是在于,为什

ExtJS中关于分页加载数据后执行一个回调函数的问题

前几天,一个项目中有用到ExtJS.之前修改的时候,只是在Store Load的时候执行一个回调,这个会导致翻页的时候,没有执行这个回调,而这个回调做的恰好是一些数据的格式验证不可或缺的. 被这个问题困扰了很久,也查了很多的关于ExtJs Store的应用和API,最终找到了一个解决的办法,其实很简单,就是在Store里面添加一个load事件的监听. new Ext.data.Store({... listeners: { "load": function (store, operat

关于js中立即执行的匿名函数写法

1 /*最流行的写法*/ 2 (function() { 3 alert("run!") 4 })(); 5 6 /* !号可以有1~正无穷个,所以这一种就可以衍生无数种方式 */ 7 !!!(function() { 8 alert("run!") 9 })(); 10 11 (function() { 12 alert("run!") 13 }).call(); 14 15 (function() { 16 alert("run!&

Javascript中的自执行匿名函数(个人理解也叫立即执行的匿名函数)的理解

格式: (function(){ //代码 })(); 包围函数(function(){})的第一对括号向脚本返回未命名的函数,随后一对空括号立即执行返回的未命名函数,括号内为匿名函数的参数. (function(arg){ alert(arg+100); })(20); // 这个例子返回120. 回来看看jquery的插件编写 (function($) { // Code goes here })(jQuery); 这样代码等同于 var a=functon($) {//code }; a(

js 如何移除一个匿名函数的绑定事件

大家都知道 addEventListener的用法 绑定事件 例如 element.addEventListener(type,handler,false); element是dom元素 type是事件比如click handler 是一个函数表达式,false 代表是冒泡阶段 true是捕获阶段 如果移除事件的话 这样写: element.removeEventListener(type,handler); 如果handler是个匿名函数呢 比如 element.addEventListene

Javascript的匿名函数与自执行

函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 函数的定义,大致可分为三种方式: 第一种:这也是最常规的一种 1 2 3 function double(x){        return 2 * x;       } 第二种:这种方法使用了Function构造函数,把参数列表和函数体都作为字符串,很不方便,不建议使用. 1 var double = new Function('x', 'return 2 * x;'); 第三种: 1

js 闭包 匿名函数 JavaScript的IIFE(即时执行方法)immediately-invoked function expression

参考:http://segmentfault.com/a/1190000000348228 http://segmentfault.com/q/1010000000442042 问题: (function(){ function a(){ alert("a"); } })();这里的(function(){xxx})(); 是什么意思,为什么这么写,有什么好处?答: function foo() {...} // 这是定义,Declaration:定义只是让解释器知道其存在,但是不会运