您的位置:首页 > 其它

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

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: