zoukankan      html  css  js  c++  java
  • 让任意线程执行一个匿名函数

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

    注意,这个和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.   
    5. class JasonQt_InvokeFromThreadHelper: public QObject  
    6. {  
    7.     Q_OBJECT  
    8.   
    9. private:  
    10.     QMutex m_mutex;  
    11.     QList< std::function<void()> > m_waitCallbacks;  
    12.   
    13. public:  
    14.     void addCallback(const std::function<void()> &callback);  
    15.   
    16. public slots:  
    17.     void onRun();  
    18. };  
    19.   
    20. class JasonQt_InvokeFromThread  
    21. {  
    22. private:  
    23.     static QMutex g_mutex;  
    24.     static QMap< QThread *, JasonQt_InvokeFromThreadHelper * > g_helpers;  
    25.   
    26. public:  
    27.     static void invoke(QThread *thread, const std::function<void()> &callback);  
    28.   
    29.     static void waitForInvoke(QThread *thread, const std::function<void()> &callback);  
    30. };  


    .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.   
    9. void JasonQt_InvokeFromThreadHelper::onRun()  
    10. {  
    11.     if(!m_waitCallbacks.isEmpty())  
    12.     {  
    13.         m_mutex.lock();  
    14.   
    15.         auto callback = m_waitCallbacks.first();  
    16.         m_waitCallbacks.pop_front();  
    17.   
    18.         m_mutex.unlock();  
    19.   
    20.         callback();  
    21.     }  
    22. }  
    23.   
    24. // JasonQt_InvokeFromThread  
    25. QMutex JasonQt_InvokeFromThread::g_mutex;  
    26. QMap< QThread *, JasonQt_InvokeFromThreadHelper * > JasonQt_InvokeFromThread::g_helpers;  
    27.   
    28. void JasonQt_InvokeFromThread::invoke(QThread *thread, const std::function<void ()> &callback)  
    29. {  
    30.     if(!(thread->isRunning()))  
    31.     {  
    32.         qDebug() << "JasonQt_InvokeFromThread::invoke: Target thread" << thread << "is not running!";  
    33.         return;  
    34.     }  
    35.   
    36.     g_mutex.lock();  
    37.   
    38.     auto it = g_helpers.find(thread);  
    39.   
    40.     if(it == g_helpers.end())  
    41.     {  
    42.         auto helper = new JasonQt_InvokeFromThreadHelper;  
    43.         helper->moveToThread(thread);  
    44.   
    45.         QObject::connect(thread, &QThread::finished, [=]()  
    46.         {  
    47.             g_mutex.lock();  
    48.   
    49.             auto it = g_helpers.find(thread);  
    50.             if(it != g_helpers.end())  
    51.             {  
    52.                 g_helpers.erase(it);  
    53.             }  
    54.   
    55.             g_mutex.unlock();  
    56.         });  
    57.   
    58.         g_helpers.insert( thread, helper );  
    59.         it = g_helpers.find(thread);  
    60.     }  
    61.   
    62.     it.value()->addCallback(callback);  
    63.   
    64.     QMetaObject::invokeMethod(it.value(), "onRun", Qt::QueuedConnection);  
    65.   
    66.     g_mutex.unlock();  
    67. }  
    68.   
    69. void JasonQt_InvokeFromThread::waitForInvoke(QThread *thread, const std::function<void ()> &callback)  
    70. {  
    71.     if(!(thread->isRunning()))  
    72.     {  
    73.         qDebug() << "JasonQt_InvokeFromThread::waitForInvoke: Target thread" << thread << "is not running!";  
    74.         return;  
    75.     }  
    76.   
    77.     g_mutex.lock();  
    78.   
    79.     auto it = g_helpers.find(thread);  
    80.   
    81.     if(it == g_helpers.end())  
    82.     {  
    83.         auto helper = new JasonQt_InvokeFromThreadHelper;  
    84.         helper->moveToThread(thread);  
    85.   
    86.         QObject::connect(thread, &QThread::finished, [=]()  
    87.         {  
    88.             g_mutex.lock();  
    89.   
    90.             auto it = g_helpers.find(thread);  
    91.             if(it != g_helpers.end())  
    92.             {  
    93.                 g_helpers.erase(it);  
    94.             }  
    95.   
    96.             g_mutex.unlock();  
    97.         });  
    98.   
    99.         g_helpers.insert( thread, helper );  
    100.         it = g_helpers.find(thread);  
    101.     }  
    102.   
    103.     it.value()->addCallback([&]()  
    104.     {  
    105.         g_mutex.unlock();  
    106.         callback();  
    107.     });  
    108.   
    109.     QMetaObject::invokeMethod(it.value(), "onRun", Qt::QueuedConnection);  
    110.   
    111.     g_mutex.lock();  
    112.     g_mutex.unlock();  
    113. }  


    测试代码:

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


    执行输出

    [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

  • 相关阅读:
    Oracle SGA详解
    oracle如何保证读一致性 第一弹
    Make命令完全详解教程
    ProC第三弹
    ProC第一弹
    ProC第二弹
    $(MAKE) , make命令
    转:跟我一起写Makefile (PDF重制版)
    [bzoj1105][POI2007]石头花园SKA
    可并堆学习
  • 原文地址:https://www.cnblogs.com/findumars/p/5342184.html
Copyright © 2011-2022 走看看