Qt新建线程的方法(有QRunnable,QThreadPool,moveToThread和QtConcurrent的例子)
看了不少Qt线程的东西,下面总结一下Qt新建一个线程的方法。
一、继承QThread
继承QThread,这应该是最常用的方法了。我们可以通过重写虚函数void QThread::run ()实现我们自己想做的操作,实现新建线程的目的。前面已经介绍了Qthread,这里就不重复了。
这种方法,我们每一次要新建一个线程都需要继承Qthread,实现一个新的类,有点不太方便。但是相对于Qrunnable,这种方法的好处就是我们可以直接调用对象的start()函数启动线程,而Qrunnable必须借助QthreadPool。
二、继承QRunnable
Qrunnable是所有可执行对象的基类。我们可以继承Qrunnable,并重写虚函数void QRunnable::run () 。我们可以用QThreadPool让我们的一个QRunnable对象在另外的线程中运行,如果autoDelete()返回true(默认),那么QThreadPool将会在run()运行结束后自动删除Qrunnable对象。可以调用void QRunnable::setAutoDelete ( bool autoDelete )更改auto-deletion标记。需要注意的是,必须在调用QThreadPool::start()之前设置,在调用QThreadPool::start()之后设置的结果是未定义的。
下面是我写的简单的例子:
class Runnable:publicQRunnable
{
//Q_OBJECT 注意了,Qrunnable不是QObject的子类。
public:
Runnable();
~Runnable();
voidrun();
protected:
private:
};
Runnable::Runnable():QRunnable()
{
}
Runnable::~Runnable()
{
cout<<"~Runnable()"<<endl;
}
void Runnable::run()
{
cout<<"Runnable::run()thread :"<<QThread::currentThreadId()<<endl;
cout<<"dosomething ...."<<endl;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<<"mainthread :"<<QThread::currentThreadId()<<endl;
Runnable runObj;
QThreadPool::globalInstance()->start(&runObj);
returna.exec();
}
由结果可看出,run()确实是在不同于主线程的另外线程中运行的,而且在运行结束后就调用了析构函数,因为默认是可以自动被销毁的。
我们可以对同一个对象多次调用QThreadPool::start(),如果是可以自动被销毁的,Qrunnable对象会在最后一个线程离开了run函数之后才被销毁的。
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<<"mainthread :"<<QThread::currentThreadId()<<endl;
Runnable runObj;
QThreadPool::globalInstance()->start(&runObj);
QThreadPool::globalInstance()->start(&runObj);
QThreadPool::globalInstance()->start(&runObj);
returna.exec();
}
我三次调用QThreadPool::globalInstance()->start(&runObj);,但是在三次都执行完之后才运行析构函数。
这种新建线程的方法的最大的缺点就是:不能使用Qt的信号—槽机制,因为Qrunnable不是继承自QObject。所以我们要想知道线程是否运行结束或获取运行结果可能会比较麻烦。还有就是我们不能直接调用run()启动线程,必须借助于QthreadPool。
但是这种方法的好处就是,可以让QThreadPool来管理线程,QThreadPool会自动的清理我们新建的Qrunnable对象。
三、使用moveToThread
首先我们必须实现继承QObject的一个类,实现我们想要的功能。
class Worker:publicQObject
{
Q_OBJECT
public:
Worker();
~Worker();
protected slots:
voidfun1();
void fun2();
private:
};
Worker::Worker():QObject()
{ }
Worker::~Worker()
{ }
void Worker::fun1()
{
cout<<"Worker::fun1() thread : "<<QThread::currentThreadId()<<endl;
}
接着创建一个对象,并调用:moveToThread ( QThread * targetThread ),让对象在新的线程中运行。
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<<"mainthread :"<<QThread::currentThreadId()<<endl;
QThread thread;
Worker work;
thread.start(); //注意记得启动线程
work.moveToThread(&thread);
//由于不能直接调用worker
//的函数,所以一般用信号触发调用
QTimer::singleShot(0,&work,SLOT(fun1()));
QTimer::singleShot(0,&work,SLOT(fun1()));
returna.exec();
}
这样就能让fun1()和fun2()都运行在thread线程中了。
需要注意的是:在work 的函数结束运行前,thread不能被析构。Thread的生命期不能小于work。否则的话程序就好崩掉了。
像下面的代码肯定是不行的。
void Dialog::startWork()
{
QThread thread;
Worker*work = new Worker;
thread.start();
work->moveToThread(&thread);
QTimer::singleShot(0,work,SLOT(fun1()));
QTimer::singleShot(0,work,SLOT(fun2()));
}
所以thread 必须是new出来的。但是这样的话,就感觉有点麻烦,我们要同时管理thread和work,因为都是new 出来,我们需要负责清理。为了避免这样的麻烦,我想到的方法是,在work类中添加一个QThread成员。
class Worker:publicQObject
{
Q_OBJECT
public:
Worker();
~Worker();
protectedslots:
voidfun1();
voidfun2();
private:
QThread m_thread;
};
Worker::Worker():QObject()
{
m_thread.start();
this->moveToThread(&m_thread);
}
这样我们在用的时候只需要newwork就行了。
四、使用QtConcurrent::run
其实前面也有用到QtConcurrent::run启动新线程了。QtConcurrent命名空间提供了很多方法可以实现并发编程,这个以后再深入探讨了,这里只是大概讲一下启动线程。还是用上面的worker代码作为例子:
void Worker::start()
{
QtConcurrent::run(this,&Worker::fun1);
QtConcurrent::run(this,&Worker::fun2);
}
QtConcurrent::run是个模板函数,有很多种形式,我们也可以让全局的函数允许在另外的线程中。
void printMes(char*mes)
{
cout<<"pprintMes(char*mes) thread : "<<QThread::currentThreadId()<<endl;
cout<<mes<<endl;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<<"mainthread :"<<QThread::currentThreadId()<<endl;
char *mes= "hello world";
QtConcurrent::run(printMes,mes);
returna.exec();
}
目前所知的新建线程的方法就大概这些了,希望对大家有用,可能还要别的,以后再继续学习了
http://blog.csdn.net/hai200501019/article/details/9899207
Qt新建线程的方法(有QRunnable,QThreadPool,moveToThread和QtConcurrent的例子)的更多相关文章
- Qt新建线程的方法(四种办法,很详细,有截图)
看了不少Qt线程的东西,下面总结一下Qt新建一个线程的方法. 一.继承QThread 继承QThread,这应该是最常用的方法了.我们可以通过重写虚函数void QThread::run ()实现我们 ...
- Nuke中新建线程的方法
最近维护合成部门的nuke工具包,发现不少工具的使用方法都很个人化,没有说明文档.这也导致artist在使用工具的时候比较感性,调整参数的时候缺少前后逻辑,长此以往,artist会产生这种意识:只要最 ...
- Winform用匿名方法新建线程的方法
作用:1.将耗时的操作放在单独的线程,加快UI的响应速度.Thread t = new Thread(delegate() { parse.ParseDay(StockCode, FileName); ...
- 【QT】继承QRunnable+QThreadPool实现多线程
往期链接: <QThread源码浅析> <子类化QThread实现多线程> <子类化QObject+moveToThread实现多线程> 本文章实例的源码地址:ht ...
- Java新建线程的3种方法
Java新建线程的3种方法 =================== Java创建线程有3种方法:(1)继承Thread;(2)实现Runnable接口:(3)实现Callable接口; 由于Java只 ...
- java 在方法中新建线程,传参和加锁详解
在实际开发中,往往在基本两三种创建线程的方法之外,还用到一个简单的创建线程调用方法的情况,代码如下: public void deleteRedisData(RedisKey redisKey){ n ...
- Qt经典—线程、事件与Qobject(耳目一新)
介绍 You’re doing it wrong. — Bradley T. Hughes 线程是qt channel里最流行的讨论话题之一.许多人加入了讨论并询问如何解决他们在运行跨线程编程时所遇到 ...
- Qt经典—线程、事件与Qobject
介绍 You’re doing it wrong. — Bradley T. Hughes 线程是qt channel里最流行的讨论话题之一.许多人加入了讨论并询问如何解决他们在运行跨线程编程时所遇到 ...
- Qt之线程基础
何为线程 线程与并行处理任务息息相关,就像进程一样.那么,线程与进程有什么区别呢?当你在电子表格上进行数据计算的时候,在相同的桌面上可能有一个播放器正在播放你最喜欢的歌曲.这是一个两个进程并行工作的例 ...
随机推荐
- innerText和innerHTML的区别
innerhtml用法 innertext用法 以及innerHTML与innertext的区别,看完这个大家以后在实际应用中,就可以选择合适的方法.尽可能的考虑到兼容性. test.innerHTM ...
- mysql 添加用户并授权(记录)
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost IDENTIFIED BY 'something' WITH GRANT OPTION ...
- 系统运维-hub, repeater, switch, router初览
repeater, hub, switch, router都是针对与osi的7层网络模型的不同层而产生的设备,逐一概览如下: repeater:中继器 是网络物理层的一种连接设备,工作在osi的物理层 ...
- QT直接支持GB18030,附它对此编码的一堆相关文档描述
http://doc.qt.io/qt-5/qtextcodec.html http://doc.qt.io/qt-5/codec-gbk.html
- Qt+SQLite数据加密的一种思路(内存数据库)
了解Qt是比较早的,可是一直没有耐心去做一个练习.近期花了差不多两周时间做了次Qt开发练习,基本完成了Qt的入门,逃脱微软平台又迈出了几小步.Qt虽然是C++的,但开发应用是比较方便的,我觉得它在界面 ...
- poco vs Boost
Wooce Yang收集整理 POCO的优点: 1) 比boost更好的线程库,特别是一个活动的方法的实现,并且还可设置线程的优先级. 2) 比 boost:asio更全面的网络库.但是boost:a ...
- HDU_1003Max Sum 简单动归
以前做过这道题目,那是还不懂状态方程.乱搞一气: #include<cstdio> #include<algorithm> using namespace std; +; in ...
- linux内核源码阅读之facebook硬盘加速flashcache之三
上一节讲到在刷缓存的时候会调用new_kcahed_job创建kcached_job,由此我们也可以看到cache数据块与磁盘数据的对应关系.上一篇:http://blog.csdn.net/lium ...
- Exam(贪心)
Exam Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- js 验证手机号 以及身份证正则表达式
手机号:① /^1(3[0-9]{9}|5[0-35-9][0-9]{8}|7[07][0-9]{8}|8[25-9][0-9]{8})$/ ② /^1(3\d|5[0-35-9]|7[07]|8[2 ...