當我們使用 QT 中的 QThread class 時, 目的就是將一部份工作放到另一條 thread 上. 當完成編程後並執行程序時會發生 Qt 回報要用的 object 不在此 thread 上.
經過網上"爬文"及多次實作後, 我的見解是 QT 中的 QThread class 的作用好像網絡上的 switch 一樣:
1.
- 啟動一條新 thread (現在我稱為 "子thread")
- 作為產生 QThread 的 thread (現在我稱為 "主thread") 與 "子thread" 的資料交換介面
例如:
class testThread : public QThread {
Q_OBJECT
private:
MyObject *a, *b;
protected:
void run();
public:
explicit testThread(QObject *parent = 0);
void startthread();
int getValue();
}
int testThread::getValue() {
return this->a->value;
}
void testThread::startthread() {
// start a new thread
this->start();
}
void testThread::run() {
this->b = new MyObject();
while(1) {
this->a->value = this->b->value;
b->inc();
}
}
void main()
{
testThread test;
test.startthread();
.....
cout << test.getValue();
}
在以上的程序中, 你會發現在 run() 中會出以下代碼:
this->a->value = this->b->value;
這是因為 object "this->b" 和 "this->a" 是在不同的 thread 內:
- "this->b" 在 "子thread" (沒錯, 所有在 run() 內所產生的物件都是在 "子thread")
- "this->a" 在 "主thread"
所以,對於外部讀取資料要求時,我們實作時需要間接的方式來讀取"子thread"的物件, 否則會出現報警.
2. 對於讀取資料, 在 Qt 內我們會經常用 Signal and Slot 功能. 但我們要留意 "子thread" 有自己的 event loop. 所以我認為做法是:
- 準備 "子thread" 的 event loop class (sub-class QEventLoop)
- 在 run() 中產生 "子thread" 的 event loop 物件
- 將 "子thread" 的 event loop 的 Signal 接到 QThread 的 Slot (main event loop)
- 再將 QThread 的 Signal 接到其他的 Slot
簡單來說 QThread 的 Signal 及 Slot 的作用就如網絡上的 switch/hub, 將 "子thread" 和 "主thread" 連在一起.
例如:
class threadEventLoop : public QEventLoop {
Q_OBJECT
.....
private:
int cnt;
signals:
void newValue(int value);
public slots:
void time_out();
}
void threadEvent::time_out() {
cnt++;
emit newValue(cnt);
}
class testThread : public QThread {
Q_OBJECT
....
protect:
void run();
signals:
void newValue(int value);
public slots:
void receive_newValue(int value);
}
void testThread::run() {
int b = 0;
threadEventLoop loop;
QTimer *timer = new QTimer();
QObject::connect(timer, SIGNAL(timeout()), &loop, SLOT(time_out()));
// 將 "子thread" 的 event loop 的 Signal 接到 QThread 的 Slot
QObject::connect(&loop, SIGNAL(newValue(int)), this, SLOT(receive_newValue(int)));
timer->start(1000);
// start event loop
loop.exec();
}
void testThread::receive_newValue(int value) {
// 將 "子thread" 的資料傳給其他 thread
emit newValue(value);
}
沒有留言:
發佈留言