最近兩天一直在圍繞著QThread的使用打轉(zhuǎn),,作為QT中的多線程支持,,QT4中的線程支持模型是很好用的,線程的切換時(shí)間粒度夠細(xì),,用起來一般不用太
多的額外控制,,自然不用多說了。但是作為QT的老版本如QT2,,QT3稍早一點(diǎn)的版本來說,,線程間的時(shí)間切換粒度很粗,照成了想要細(xì)粒度的控制的話,,必須
與自己的一套控制策略才行,。今天借用一個(gè)小小的QThread相關(guān)的實(shí)例程序,從不同的角度來剖析一下,,做個(gè)記錄,,同時(shí)也分享給正在學(xué)習(xí)的各位同道中人:
實(shí)例:本實(shí)例很簡單,只涉及到三個(gè)源文件;thread.h thread.cpp main.cpp
前兩個(gè)是關(guān)于本例的實(shí)際線程類的關(guān)聯(lián)文件,。main.cpp就不用說了吧,,相信大家都有這個(gè)意識(shí)。
貼上源碼:
thread.h
#include<qthread.h>
#include<stdio.h>
#include<qmutex.h>
#include<qmutex.h>
#include <qwaitcondition.h>
extern QWaitCondition mycond;
extern QMutex mutex;
class MyThread :public QThread
{
public:
MyThread(const QString &);
virtual void run();
private:
QString str;
};
thread.cpp
#include "thread.h"
QWaitCondition mycond;
QMutex mutex;
MyThread::MyThread(const QString & s)
{
str =
s;
}
void MyThread::run()
{
for(int i =
0 ;i<100 ;i++
) {
mutex.lock();
if(!(i%10))
{mycond.wakeAll();
if(i!=90)
mycond.wait(&mutex);
printf("swith\n");}
mutex.unlock();
printf("%s",(const
char*)str);
printf("%d",i);
}
}
main.cpp
#include"thread.h"
int main()
{
MyThread a(QString("A"));
MyThread b(QString("B"));
b.start();//自動(dòng)調(diào)用run(),否則即使該線程創(chuàng)建,,也是一開始就掛起
a.start();
//要等待線程a,b都退出
a.wait();
b.wait();
}
本次分析重點(diǎn)在與在QT3.1的環(huán)境下對(duì)線程的時(shí)間粒度進(jìn)行自己的控制,,源碼中有相關(guān)的紅色或標(biāo)記,那些就是本例分析的關(guān)鍵所在,,藍(lán)色標(biāo)記實(shí)現(xiàn)了
線程間的按規(guī)定的時(shí)間粒度切換,而紅色的則是解決程序的關(guān)鍵細(xì)節(jié)問題的地方,。通過改變紅色標(biāo)記的改動(dòng)導(dǎo)致的試驗(yàn)結(jié)果進(jìn)行相應(yīng)的分析,。首先分析下給程序的本
來期望實(shí)現(xiàn)的功能,由于QT自身切換的時(shí)間粒度過大,,本程序通過QWaitCondition來對(duì)線程進(jìn)行控制,,使得兩個(gè)線程實(shí)體a,b能夠以每運(yùn)行十次
就交換的控制權(quán)的節(jié)奏來運(yùn)行,。每個(gè)線程共運(yùn)行100次,,每十次進(jìn)行一切換,。
按照上面的源碼,不作改動(dòng),,編譯后在rh9.0下的運(yùn)行結(jié)果是:
swith
B0B1B2B3B4B5B6B7B8B9swith
A0A1A2A3A4A5A6A7A8A9swith
B10B11B12B13B14B15B16B17B18B19swith
A10A11A12A13A14A15A16A17A18A19swith
B20B21B22B23B24B25B26B27B28B29swith
A20A21A22A23A24A25A26A27A28A29swith
B30B31B32B33B34B35B36B37B38B39swith
A30A31A32A33A34A35A36A37A38A39swith
B40B41B42B43B44B45B46B47B48B49swith
A40A41A42A43A44A45A46A47A48A49swith
B50B51B52B53B54B55B56B57B58B59swith
A50A51A52A53A54A55A56A57A58A59swith
B60B61B62B63B64B65B66B67B68B69swith
A60A61A62A63A64A65A66A67A68A69swith
B70B71B72B73B74B75B76B77B78B79swith
A70A71A72A73A74A75A76A77A78A79swith
B80B81B82B83B84B85B86B87B88B89swith
B90B91B92B93B94B95B96B97B98B99swith
A80A81A82A83A84A85A86A87A88A89swith
A90A91A92A93A94A95A96A97A98A99
成功的完成了程序所要完成的功能,。A和B都成功的答應(yīng)了99次。for循環(huán)中的100,,限定了這個(gè)次數(shù),,同時(shí)i%10及其中的語句通過
QWaitCondition控制了所在線程的等待,將控制權(quán)交給其他線程,。由于是交替的進(jìn)行掛起自己,,等待其他線程運(yùn)行,在讓自己被喚醒的過程,。當(dāng)最后
一次交替時(shí),,只作喚醒其他線程,不掛起自己,,這樣能保證所有線程不會(huì)陷入空等狀態(tài),,使得程序在完成工作后可以安全退出。同時(shí)可見,,在最后的80-99次中
沒發(fā)生向前面那樣的交替,,原因在于自己只是讓其他線程喚醒,并沒有自我掛起,,所以在屬于自己的時(shí)間片就能完成自己80-99的工作了,。
最后一次掛起點(diǎn)不能掛起,在這里即是在90次時(shí),,(由于i<100/i<=99)不然由于最終有一個(gè)線程的最后一次掛起沒人去喚醒,,導(dǎo)致程序死等,下面將介紹死等的狀況,。
修改i<100為i<=100,,此時(shí)最后一次掛起點(diǎn)將變?yōu)?00,如果其他地方不變的話,,該程序運(yùn)行后效果為:
swith
B0B1B2B3B4B5B6B7B8B9swith
A0A1A2A3A4A5A6A7A8A9swith
B10B11B12B13B14B15B16B17B18B19swith
A10A11A12A13A14A15A16A17A18A19swith
B20B21B22B23B24B25B26B27B28B29swith
A20A21A22A23A24A25A26A27A28A29swith
B30B31B32B33B34B35B36B37B38B39swith
A30A31A32A33A34A35A36A37A38A39swith
B40B41B42B43B44B45B46B47B48B49swith
A40A41A42A43A44A45A46A47A48A49swith
B50B51B52B53B54B55B56B57B58B59swith
A50A51A52A53A54A55A56A57A58A59swith
B60B61B62B63B64B65B66B67B68B69swith
A60A61A62A63A64A65A66A67A68A69swith
B70B71B72B73B74B75B76B77B78B79swith
A70A71A72A73A74A75A76A77A78A79swith
B80B81B82B83B84B85B86B87B88B89swith
swith
A80A81A82A83A84A85A86A87A88A89swith
A90A91A92A93A94A95A96A97A98A99B90B91B92B93B94B95B96B97B98B99swith(程序中沒切換,,系統(tǒng)切換了)
第一百次打印完不成!?。,。?/strong>原因就是第一百次時(shí),,發(fā)生最后一次掛起點(diǎn),,但是最后a被解掛,但是B一直死等。程序退出不了,。最后一次掛起點(diǎn)之后的數(shù)據(jù)均無法輸出,。這是i最大值可取到100到109,效果一樣,。
結(jié)果是:最后一組數(shù)據(jù)(10個(gè))都打不出來(A和B一樣)此時(shí)的if(i!=90)只是控制了倒數(shù)第二個(gè)掛起點(diǎn)不再掛起和切換,,至于是否掛起和切換還要根據(jù)其時(shí)間片是否用完來確定。即是同樣的程序運(yùn)行效果可能是:
swith
B0B1B2B3B4B5B6B7B8B9swith
A0A1A2A3A4A5A6A7A8A9swith
B10B11B12B13B14B15B16B17B18B19swith
A10A11A12A13A14A15A16A17A18A19swith
B20B21B22B23B24B25B26B27B28B29swith
A20A21A22A23A24A25A26A27A28A29swith
B30B31B32B33B34B35B36B37B38B39swith
A30A31A32A33A34A35A36A37A38A39swith
B40B41B42B43B44B45B46B47B48B49swith
A40A41A42A43A44A45A46A47A48A49swith
B50B51B52B53B54B55B56B57B58B59swith
A50A51A52A53A54A55A56A57A58A59swith
B60B61B62B63B64B65B66B67B68B69swith
A60A61A62A63A64A65A66A67A68A69swith
B70B71B72B73B74B75B76B77B78B79swith
A70A71A72A73A74A75A76A77A78A79swith
B80B81B82B83B84B85B86B87B88B89swith
B90B91B92B93B94B95B96B97B98B99swith
A80A81A82A83A84A85A86A87A88A89swith
A90A91A92A93A94A95A96A97A98A99swith(程序沒切換,,系統(tǒng)也沒切換)
在主程序中如果不加wait語句,,程序會(huì)出現(xiàn)QThread object destroyed while
thread is still running.如果wait語句加過了,沒什么錯(cuò)誤出現(xiàn),。