Qt新建线程的方法(四种办法,很详细,有截图)
看了不少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新建线程的方法(四种办法,很详细,有截图)的更多相关文章
- Qt新建线程的方法(有QRunnable,QThreadPool,moveToThread和QtConcurrent的例子)
看了不少Qt线程的东西,下面总结一下Qt新建一个线程的方法. 一.继承QThread 继承QThread,这应该是最常用的方法了.我们可以通过重写虚函数void QThread::run ()实现我们 ...
- js检测数据类型四种办法
面试题中经常会考js数据类型检测,今天我来分享一下js中常用的四种方法判断数据类型,欢迎指点更正. 废话不多说,直入正题. 1.typeof console.log(typeof "&quo ...
- Java-五种线程池,四种拒绝策略,三种阻塞队列(转)
Java-五种线程池,四种拒绝策略,三种阻塞队列 三种阻塞队列: BlockingQueue<Runnable> workQueue = null; workQueue = n ...
- 线程终止的四种方式,interrupt 方法使用的简单介绍。
一 正常结束. package com.aaa.threaddemo; /* 一 终止线程的四种方式? * 程序运行结束,线程终止. * */ public class ThreadTerminati ...
- java并发编程(四)守护进程 线程阻塞的四种情况
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17099981 守护线程 Java中有两类线程:User Thread(用户线程).Da ...
- 转:【Java并发编程】之四:守护线程与线程阻塞的四种情况
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17099981 守护线程 Java中有两类线程:User Thread(用户线 ...
- C++线程同步的四种方式(Windows)
为什么要进行线程同步? 在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作.更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解.正常情况下对这种处理结果的 ...
- java线程实现的四种方式
java多线程的实现可以通过以下四种方式 1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法 3.通过Callable和FutureTask创建线程 4.通过线程池创 ...
- 【Java并发编程】:守护线程与线程阻塞的四种情况
守护线程 JAVA中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 用户线程即运行在前台的线程,而守护线程是运行在后台的线程. 守护线程作用是为其他前台线程的运 ...
随机推荐
- pat_1
2-0 2-1 #include <stdio.h> int main() { int inch,foot,cm; scanf("%d",&cm); foot= ...
- NPOI导出多张图片到Excel
常用NPOI导出数据到excel,但没有试过如何导出图片.NPOI最大的特点就是不依赖于Excel组件,服务端不需要安装Excel.在单元格中插入图片主要是用HSSFClientAnchor对象.他有 ...
- 基于HCE移动支付研究报告
1. 概念 HCE(host-based card emulation),即基于主机的卡模拟.在一部配备NFC功能的手机实现卡模拟,目前有两种方式:一种是基于硬件的,称为虚拟卡模式(Virtual C ...
- cf467B Fedor and New Game
B. Fedor and New Game time limit per test 1 second memory limit per test 256 megabytes input standar ...
- 何谓Dandy?它是一种着装风格
何谓Dandy?它是一种着装风格_女性_腾讯网 何谓Dandy?它是一种着装风格 2012年02月17日09:47腾讯专稿我要评论(0) 字号:T|T 何谓Dandyism?它是一种风格,词根Da ...
- 浅谈C语言中的强符号、弱符号、强引用和弱引用
摘自http://www.jb51.net/article/56924.htm 浅谈C语言中的强符号.弱符号.强引用和弱引用 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014- ...
- linux shell自定义函数(定义、返回值、变量作用域)介绍
http://www.jb51.net/article/33899.htm linux shell自定义函数(定义.返回值.变量作用域)介绍 linux shell 可以用户定义函数,然后在shell ...
- nodejs面试
1. PM2相关 1. PM2的主要功能?*答案:在Node.js进程挂掉以后自动重启进程,并且能够方便的实现Node.js的集群模式* 2. 如何查看当前是否适合重启服务?*答案:pm2 monit ...
- php算法之快速排序
/** * 快速排序 * 原理: * 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists). * 最差时间复杂度 O(n*n) * ...
- linux-telnet服务配置
Telnet服务的配置:一.安装telnet软件包(通常要两个)1. telnet-client (或 telnet),这个软件包提供的是 telnet 客户端程序: 2. telnet-server ...