Qt新建執行緒的方法(四種辦法,很詳細,有截圖)
看了不少Qt執行緒的東西,下面總結一下Qt新建一個執行緒的方法。
一、繼承QThread
繼承QThread,這應該是最常用的方法了。我們可以通過重寫虛擬函式void QThread::run ()實現我們自己想做的操作,實現新建執行緒的目的。前面已經介紹了Qthread,這裡就不重複了。
這種方法,我們每一次要新建一個執行緒都需要繼承Qthread,實現一個新的類,有點不太方便。但是相對於Qrunnable,這種方法的好處就是我們可以直接呼叫物件的start()函式啟動執行緒,而Qrunnable必須藉助QthreadPool。
二、繼承QRunnable
Qrunnable是所有可執行物件的基類。我們可以繼承Qrunnable,並重寫虛擬函式void QRunnable::run () 。我們可以用
下面是我寫的簡單的例子:
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。(我們可以讓類同時繼承於QObject和QRunnable,就可以使用訊號和槽了)所以我們要想知道執行緒是否執行結束或獲取執行結果可能會比較麻煩。還有就是我們不能直接呼叫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