① 誰能說一下在Qt中使用多線程有哪些需要注意的事項呢
在Qt中使用多線程,目前就我使用過的有兩種,一是子類化QThread,重寫run函數,在run函數里實現自己的代碼,這一部分代碼通常是比較耗時,或者乾脆直接阻塞的。比如一個while循環,設置一個標志,判斷循環結束。
這樣的例子在網上有很多,就不寫了。
這樣寫的話,會有一些東西需要了解。
子類化QThread的方法,只有run函數裡面的內容是執行在子線程里的,其他的部分,比如槽函數什麼的還是在主線程里執行(假設是在主線程開啟的該子線程)。
還有一種方法,是子類化QObject,新建一個線程,然後使用MoveToThread把這個類的對象移到新建的線程中,這種做法使得它所有的槽函數都是執行在新開辟的線程裡面。
如果直接(QObject對象).abc()的話,這個成員函數是在主進程內執行,可能會出現"QObject::killTimer: timers
cannot be stopped from another thread"的運行錯誤。
使用第二種方法的話,貌似會遇到這樣的問題:如果在一個槽函數中把子線程阻塞,其他的槽函數無法接受來自主線程
② 請問Qt中使用WinThread通常如何實現線程間通信如傳遞QByteArray
在Qt裡面是QThread吧,如果是多線程要在一個類裡面也沒啥問題,效率那主要就是考慮你線程干什麼工作了,在Qt裡面,你可以直接繼承QThread類並實現它的run方法就可以了
class Worker_1 : public QThread
{
public:
Worker_1();
~Worker_1();
protected:
virtual void run() { // do somthing }
}
class Work_2 //你同樣可以寫出Work_2這個類
class WorkManager : QObject
{
Q_OBJECT
//......
public:
void start()
{
w1.start();
w2.start();
}
private:
Worker_1 w1;
Worker_2 w2;
}
// test main function
int main(void)
{
WorkManager wm;
wm.start();
while(1) QThread::sleep(300000);
}
在Qt裡面QMutex、QSemphore只可以用來做線程間同步,如果你涉及到多線程共享資源的訪問的話
兩個線程間傳遞QByteArray,如果這個QbyteArray非常大的話,你建議你使用共享內存的方式,當然如果情況還好,可以使用Qt的信號與槽機制
③ 用QThread創建的線程如何關閉
QT線程有3個函數可以關閉線程,分別是:
void quit ()
相當於exit(0)。
void exit ( int returnCode = 0 )
調用exit後,thread將退出event loop,並從exec返回,exec的返回值就是returnCode。
通常returnCode=0表示成功,其他值表示失敗。
void terminate ()
結束線程,線程是否立即終止取決於操作系統。
線程被終止時,所有等待該線程Finished的線程都將被喚醒。
terminate是否調用取決於setTerminationEnabled ( bool enabled = true )開關。
其中quit與terminate是槽,可以直接用信號連接關閉線程,不過一般不建議使用terminate,還有想關閉線程,最好像下面例子;
直接調用stop介面就行了,線程就會關閉
class Thread : public QThread
{
Q_OBJECT
public:
Thread();
void setMessage(const QString &message);
void stop();
protected:
void run();
private:
QString messageStr;
volatile bool stopped;
};
Thread::Thread()
{
stopped = false;
}
void Thread::run()
{
while (!stopped)
std::cerr << qPrintable(messageStr);
stopped = false;
std::cerr << std::endl;
}
void Thread::stop()
{
stopped = true;
}
④ qthread類中能添加槽函數嗎
主線程(信號)QThread(槽)
這是 Qt Manual 和 例子中普遍採用的方法。 但由於manual沒說槽函數是在主線程執行的,所以不少人都認為它應該是在次線程執行了。
定義一個 Dummy 類,用來發信號
定義一個 Thread 類,用來接收信號
⑤ 怎樣正確的使用QThread類
要實現一個線程很簡單,寫一個函數,綁定一些數據,如果有必要的話,可以使用 mutex 或者其他方法來保證和線程的安全交互。
無論是 Win32、POSIX 或其他線程,工作原理都基本相同,並相當可靠。至少我敢說比 socket 更容易使用和處理。
簡述
worker-object
worker-object
使用 QThread 時,最主要的事情是把它當成一個線程對象的封裝。此封裝提供了信號、槽和方法,可以輕松地使用 Qt 項目中的線程對象。這說明了子類化 QThread 並實現其 run() 函數是非常錯誤的。
一個 QThread 應該更像一個普通線程實例:准備一個 QObject 類和所有想要的功能,然後創建一個新的QThread,使用 moveToThread(QThread *) 將 QObject 對象移動至線程中,並調用 QThread 實例的 start() 函數。就這樣,再設置適當的信號/槽連接使它正常退出,所有的事情就都做完了。
⑥ 如何使用 qthread run 獲取參數
創建qthread的自定義子類QMyThread。QMyThread增加成員來傳遞參數。
用QMyThread創建線程時,並把參數賦值給QMyThread對象。run的時候,直接從QMyThread對象中獲取參數。
⑦ qthread如何啟動多個線程
1. 引言
多線程對於需要處理耗時任務的應用很有用,一方面響應用戶操作、更新界面顯示,另一方面在「後台」進行耗時操作,比如大量運算、復制大文件、網路傳輸等。
使用Qt框架開發應用程序時,使用QThread類可以方便快捷地創建管理多線程。而多線程之間的通信也可使用Qt特有的「信號-槽」機制實現。
下面的說明以文件復制為例。主線程負責提供交互界面,顯示復制進度等;子線程負責復制文件。最後附有可以執行的代碼。
2. QThread使用方法1——重寫run()函數
第一種使用方法是自己寫一個類繼承QThread,並重寫其run()函數。
大家知道,C/C++程序都是從main()函數開始執行的。main()函數其實就是主進程的入口,main()函數退出了,則主進程退出,整個進程也就結束了。
而對於使用Qthread創建的進程而言,run()函數則是新線程的入口,run()函數退出,意味著線程的終止。復制文件的功能,就是在run()函數中執行的。
下面舉個文件復制的例子。自定義一個類,繼承自Qthread
CopyFileThread: public QThread
{
Q_OBJECTpublic:
CopyFileThread(QObject * parent = 0);protected: void run(); // 新線程入口// 省略掉一些內容}
在對應的cpp文件中,定義run()
void CopyFileThread::run(){ // 新線程入口
// 初始化和操作放在這里}
將這個類寫好之後,在主線程的代碼中生成一個CopyFileThread的實例,例如在mainwindow.cpp中寫:
// mainwindow.h中CopyFileThread * m_cpyThread;// mainwindow.cpp中m_cpyThread = new CopyFileThread;
在要開始復制的時候,比如按下「復制」按鈕後,讓這個線程開始執行:
m_cpyThread->start();
注意,使用start()函數來啟動子線程,而不是run()。start()會自動調用run()。
線程開始執行後,就進入run()函數,執行復制文件的操作。而此時,主線程的顯示和操作都不受影響。
如果需要進行對復制過程中可能發生的事件進行處理,例如界面顯示復制進度、出錯返回等等,應該從CopyFileThread中發出信號(signal),並事先連接到mainwindow的槽,由這些槽函數來處理事件。
3. QThread使用方法2——moveToThread()
如果不想每執行一種任務就自定義一個新線程,那麼可以自定義用於完成任務的類,並讓它們繼承自QObject。例如,自定義一個FileCopier類,用於復制文件。
class FileCopier : public QObject
{
Q_OBJECTpublic: explicit FileCopier(QObject *parent = 0);public slots: void startCopying(); void cancelCopying();
}
注意這里我們定義了兩個槽函數,分別用於復制的開始和取消。
這個類本身的實例化是在主線程中進行的,例如:
// mainwindow.h中private:
FileCopier* m_copier;// mainwindow.cpp中,初始化時
m_copier = new FileCopier;
此時m_copier還是屬於主線程的。要將其移動到子線程處理,需要首先聲明並實例化一個QThread:
// mainwindow.h中signals: void startCopyRsquested();private:
QThread * m_childThread; // m_copier將被移動到此線程執行// mainwindow.cpp中,初始化時
m_childThread = new QThread; // 子線程,本身不負責復制
然後使用moveToThread()將m_copier移動到新線程。注意moveToThread()是QObject的公有函數,因此用於復制文件的類FileCopier必須繼承自QObject。移動之後啟動子線程。此時復制還沒有開始。
m_copier->moveToThread(m_childThread); // 將實例移動到新的線程,實現多線程運行
m_childThread->start(); // 啟動子線程
注意一定要記得啟動子線程,否則線程沒有運行,m_copier的功能也無法執行。
要開始復制,需要使用信號-槽機制,觸發FileCopier的槽函數實現。因此要事先定義信號並連接:
// mainwindow.h中signals: void startCopyRsquested();// mainwindow.cpp中,初始化時// 使用信號-槽機制,發出開始指令
connect(this, SIGNAL(startCopyRsquested()), m_copier, SLOT(startCopying()));
當按下「復制」按鈕後,發出信號。
emit startCopyRsquested(); // 發送信號
m_copier在另一個線程接收到信號後,觸發槽函數,開始復制文件。
4.常見問題
4.1. 子線程中能不能進行UI操作?
Qt中的UI操作,比如QMainWindow、QWidget之類的創建、操作,只能位於主線程!
這個限制意味著你不能在新的線程中使用QDialog、QMessageBox等。比如在新線程中復制文件出錯,想彈出對話框警告?可以,但是必須將錯誤信息傳到主線程,由主線程實現對話框警告。
因此一般思路是,主線程負責提供界面,子線程負責無UI的單一任務,通過「信號-槽」與主線程交互。
4.2. QThread中的哪些代碼屬於子線程?
QThread,以及繼承QThread的類(以下統稱QThread),他們的實例都屬於新線程嗎?答案是:不。
需要注意的是,QThread本身的實例是屬於創建該實例的線程的。比如在主線程中創建一個QThread,那麼這個QThread實例本身屬於主線程。當然,QThread會開辟一個新線程(入口是run()),但是QThread本身並不屬於這個新線程。也就是說,QThread本身的成員都不屬於新線程,而且在QThread構造函數里通過new得到的實例,也不屬於新線程。這一特性意味著,如果要實現多線程操作,那麼你希望屬於新線程的實例、變數等,應該在run()中進行初始化、實例化等操作。本文給出的例子就是這樣操作的。
如果你的多線程程序運行起來,會出現關於thread的報警,思考一下,各種變數、實例是不是放對了位置,是不是真的位於新的線程里。
4.3. 怎麼查看是不是真的實現了多線程?
可以列印出當前線程。對於所有繼承自QObject的類,例如QMainwindow、QThread,以及自定義的各種類,可以調用QObject::thread()查看當前線程,這個函數返回的是一個QThread的指針。例如用qDebug()列印:
在mainwindow.cpp的某個函數里、QThread的run()函數里、自定義類的某個函數里,寫上:
qDebug() << "Current thread:" << thread();
對比不同位置列印的指針,就可以知道它們是不是位於同一個線程了。
5.範例
範例實現了多線程復制文本文件。
提供的範例文件可用QtCreator編譯運行。界面如下(不同的操作系統略有不同):
範例中實現了本文介紹的兩種方法,同時也給出了單線程復制對比。打鉤選擇不同的復制方法。可以發現,在使用多線程的時候,界面不會假死,第二根進度條的動畫是持續的;而使用單線程復制的時候,「取消」按鈕按不動,界面假死,而且第二根進度條的動畫也停止了。
由於範例處理的文件很小,為了讓復制過程持續較長時間以便使得現象明顯,復制文件的時候,每復制一行加入了等待。
範例代碼:
https://github.com/Xia-Weiwen/CopyFile
⑧ python pyqt5 qthread有哪些方法
用例子說明吧,常用的不多
PyQt中的線程類 QtCore.QThread ,使用時繼承QThread類
啟動界面的線程暫稱為UI線程。界面執行命令時都在自己的UI線程中。
如果在UI線程中執行網路連接和資料庫操作等耗時的操作,界面會被卡住,Windows下有可能會出現「無響應」的警告。
阻塞UI線程會降低用戶體驗和應用穩定性。因此我們可以把耗時操作放在線程中去執行。
QThread代表一個線程,我們可以復寫run函數來執行我們要的操作。
QThread可以使用 QtCore.pyqtSignal 來與界面交互和傳輸數據。
PyQt4 QThread 代碼示例
•Python2.7
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore
from PyQt4.QtCore import QCoreApplication
from PyQt4.QtGui import QWidget, QPushButton, QApplication, QTextBrowser
class TimeThread(QtCore.QThread):
signal_time = QtCore.pyqtSignal(str, int) # 信號
def __init__(self, parent=None):
super(TimeThread, self).__init__(parent)
self.working = True
self.num = 0
def start_timer(self):
self.num = 0
self.start()
def run(self):
while self.working:
print "Working", self.thread()
self.signal_time.emit("Running time:", self.num) # 發送信號
self.num += 1
self.sleep(1)
class TimeDialog(QWidget):
def __init__(self):
super(TimeDialog, self).__init__()
self.timer_tv = QTextBrowser(self)
self.init_ui()
self.timer_t = TimeThread()
self.timer_t.signal_time.connect(self.update_timer_tv)
def init_ui(self):
self.resize(300, 200)
self.setWindowTitle('TimeDialog')
self.timer_tv.setText("Wait")
self.timer_tv.setGeometry(QtCore.QRect(10, 145, 198, 26))
self.timer_tv.move(0, 15)
btn1 = QPushButton('Quit', self)
btn1.setToolTip('Click to quit')
btn1.resize(btn1.sizeHint())
btn1.move(200, 150)
btn1.clicked.connect(QCoreApplication.instance().quit)
start_btn = QPushButton('Start', self)
start_btn.setToolTip("Click to start")
start_btn.move(50, 150)
self.connect(start_btn, QtCore.SIGNAL("clicked()"), self.click_start_btn)
def click_start_btn(self):
self.timer_t.start_timer()
def update_timer_tv(self, text, number):
self.timer_tv.setText(self.tr(text + " " + str(number)))
if __name__ == '__main__':
app = QApplication(sys.argv)
time_dialog = TimeDialog()
time_dialog.show()
sys.exit(app.exec_())
QThread中使用的信號 signal_time = QtCore.pyqtSignal(str, int) 指定了參數str和int
發送信號 self.signal_time.emit("Running time:", self.num)
外部接收信號 self.timer_t.signal_time.connect(self.update_timer_tv)
信號連接到方法 update_timer_tv(self, text, number) ,注意信號與方法的參數要一一對應
使用中我們可以定義多種不同的信號 QtCore.pyqtSignal
啟動線程,調用 start()
⑨ QT線程如何使用的
包含QThread頭文件
創建一個對象指針 QThread *myThread;
myThread = new QThread;
myThread->start();
同時需要在新建的QThread線程文件中的run函數裡面添加你想要用的代碼即可。
建議看看QT開發的書,例子很多。也可以看幫主文檔的。