天天看點

[Qt教程] 第39篇 網絡(九)程序和線程 [Qt教程] 第39篇 網絡(九)程序和線程

<a target="_blank" href="http://bbs.qter.org/forum.php?mod=viewthread&amp;tid=580">樓主</a>

[Qt教程] 第39篇 網絡(九)程式和線程 [Qt教程] 第39篇 網絡(九)程式和線程

 發表于 2013-8-29 15:48:56 | 檢視:

415| 回複: 0

程序和線程

版權聲明

該文章原創于作者yafeilinux,轉載請注明出處!

導語

在前面的幾節内容中講解了qt網絡程式設計的一些基本内容,這一節來看一下在qt中程序和線程的基本應用。

環境:windows

xp + qt 4.8.5+qt creator2.8.0

目錄

一、程序

二、線程

正文

    在設計一個應用程式時,有時不希望将一個不太相關的功能內建到程式中,或者是因為該功能與目前設計的應用程式聯系不大,或者是因為該功能已經可以使用現成的程式很好的實作了,這時就可以在目前的應用程式中調用外部的程式來實作該功能,這就會使用到程序。qt應用程式可以很容易的啟動一個外部應用程式,而且qt也提供了在多種程序間通信的方法。

    qt的qprocess類用來啟動一個外部程式并與其進行通信。下面我們來看一下怎麼在qt代碼中啟動一個程序。

1.首先建立qtgui應用。

工程名稱為“myprocess”,其他選項保持預設即可。

2.然後設計界面。

在設計模式往界面上拖入一個push button部件,修改其顯示文本為“啟動一個程序”。

3.修改槽。

在按鈕上點選滑鼠右鍵,轉到其clicked()信号對應的槽,更改如下:

void mainwindow::on_pushbutton_clicked()

{

     myprocess.start("notepad.exe");

}

4.進入mainwindow.h檔案添加代碼。

先添加頭檔案包含:#include &lt;qprocess&gt;,然後添加私有對象定義:qprocess myprocess;

5.運作程式。

當單擊界面上的按鈕時就會彈出一個記事本程式。

這裡我們使用qprocess對象運作了windows系統下的記事本程式(即notepad.exe程式),因為該程式在系統目錄中,是以這裡不需要指定其路徑。大家也可以運作其他任何的程式,隻需要指定其具體路徑即可。我們看到,可以使用start()來啟動一個程式,有時啟動一個程式時需要指定啟動參數,這種情況在指令行啟動程式時是很常見的,下面來看一個例子,還在前面的例子的基礎上進行更改。

1.在mainwindow.h檔案中添加代碼。

添加私有槽:

private slots:

    void showresult();

2.在mainwindow.cpp檔案中添加代碼。

(1)先添加頭檔案包含:#include &lt;qdebug&gt;,然後在構造函數中添加如下代碼:

connect(&amp;myprocess,signal(readyread()), this, slot(showresult()));

(2)然後添加showresult()槽的定義:

void mainwindow::showresult()

    qdebug()

&lt;&lt; "showresult: " &lt;&lt; endl

            &lt;&lt; qstring(myprocess.readall());

(3)最後将前面按鈕的單擊信号對應的槽更改為:

    qstring program = "cmd.exe";

    qstringlist arguments;

    arguments &lt;&lt; "/c dir&amp;pause";

    myprocess.start(program,

arguments);

    這裡在啟動windows下的指令行提示符程式cmd.exe時為其提供了指令作為參數,這樣可以直接執行該指令。當指令執行完以後可以執行showresult()槽來顯示運作的結果。這裡為了可以顯示結果中的中文字元,使用了qstring()進行編碼轉換。這需要在mian()函數中添加代碼。

3. 為了確定可以顯示輸出的中文字元,在main.cpp檔案中添加代碼。

先添加頭檔案包含#include &lt;qtextcodec&gt;,然後在main()函數第一行代碼下面,添加如下一行代碼:

qtextcodec::setcodecforcstrings(qtextcodec::codecforlocale());

4.運作程式。

按下界面上的按鈕,會在qt creator中的應用程式輸出欄中輸出指令的執行結果。

    對于qt中程序進一步的使用可以參考qprocess類的幫助文檔。在qt中還提供了多種程序間通信的方法,大家可以在qt幫助中檢視inter-processcommunication

in qt關鍵字對應的文檔。

qt提供了對線程的支援,這包括一組與平台無關的線程類,一個線程安全的發送事件的方式,以及跨線程的信号-槽的關聯。這些使得可以很容易的開發可移植的多線程qt應用程式,可以充分利用多處理器的機器。多線程程式設計也可以有效的解決在不當機一個應用程式的使用者界面的情況下執行一個耗時的操作的問題。關于線程的内容,大家可以在qt幫助中參考thread

support in qt關鍵字。

(一)啟動一個線程

    qt中的qthread類提供了平台無關的線程。一個qthread代表了一個在應用程式中可以獨立控制的線程,它與程序中的其他線程分享資料,但是是獨立執行的。相對于一般的程式都是從main()函數開始執行,qthread從run()函數開始執行。預設的,run()通過調用exec()來開啟事件循環。要建立一個線程,需要子類化qthread并且重新實作run()函數。

    每一個線程可以有自己的事件循環,可以通過調用exec()函數來啟動事件循環,可以通過調用exit()或者quit()來停止事件循環。在一個線程中擁有一個事件循環,可以使它能夠關聯其他線程中的信号到本線程的槽上,這使用了隊列關聯機制,就是在使用connect()函數進行信号和槽的關聯時,将qt::connectiontype類型的參數指定為qt::queuedconnection。擁有事件循環還可以使該線程能過使用需要事件循環的類,比如qtimer和qtcpsocket類等。注意,線上程中是無法使用任何的部件類的。

    下面來看一個在圖形界面程式中啟動一個線程的例子,在界面上有兩個按鈕,一個用于開啟一個線程,一個用于關閉該線程。

1.建立項目。

    建立qt gui應用,名稱為“mythread”,類名為“dialog”,基類選擇qdialog。

2.設計界面。

    完成項目建立後進入設計模式,向界面中放入兩個push button按鈕,将第一個按鈕的顯示文本更改為“啟動線程”,将其objectname屬性更改為startbutton;将第二個按鈕的顯示文本更改為“終止線程”,将其objectname屬性更改為stopbutton,将其enabled屬性取消選中。

3.添加自定義線程類。

    向項目中添加新的c++類,類名設定為“mythread”,基類設定為“qthread”,類型資訊選擇“繼承自qobject”。完成後進入mythread.h檔案,先添加一個公有函數聲明:

void stop();

然後再添加一個函數聲明和一個變量的定義:

protected:

    void run();

private:

    volatile bool stopped;

    這裡stopped變量使用了volatile關鍵字,這樣可以使它在任何時候都保持最新的值,進而可以避免在多個線程中通路它時出錯。然後進入mythread.cpp檔案中,先添加頭檔案#include

&lt;qdebug&gt;,然後在構造函數中添加如下代碼:

stopped = false;

    這裡将stopped變量初始化為false。下面添加run()函數的定義:

void mythread::run()

    qreal i = 0;

    while (!stopped)

        qdebug() &lt;&lt; qstring("in mythread: %1").arg(i++);

    stopped = false;

    這裡一直判斷stopped變量的值,隻要它為false,那麼就一直列印字元串。下面添加stop()函數的定義:

void mythread::stop()

    stopped = true;

    在stop()函數中将stopped變量設定為了true,這樣便可以結束run()函數中的循環,進而從run()函數中退出,這樣整個線程也就結束了。這裡使用了stopped變量來實作了程序的終止,并沒有使用危險的terminate()函數。

4.在dialog類中使用自定義的線程。

先到dialog.h檔案中,添加頭檔案包含:

#include "mythread.h"

    然後添加私有對象的定義:

mythread thread;

下面到設計模式,分别進入兩個按鈕的單擊信号對應的槽,更改如下:

// 啟動線程按鈕

void dialog::on_startbutton_clicked()

    thread.start();

    ui-&gt;startbutton-&gt;setenabled(false);

    ui-&gt;stopbutton-&gt;setenabled(true);

// 終止線程按鈕

void dialog::on_stopbutton_clicked()

    if (thread.isrunning()) {

        thread.stop();

        ui-&gt;startbutton-&gt;setenabled(true);

        ui-&gt;stopbutton-&gt;setenabled(false);

    }

    在啟動線程時調用了start()函數,然後設定了兩個按鈕的狀态。在終止線程時,先使用isrunning()來判斷線程是否在運作,如果是,則調用stop()函數來終止線程,并且更改兩個按鈕的狀态。現在運作程式,按下“啟動線程”按鈕,檢視應用程式輸出欄的輸出,然後再按下“終止線程”按鈕,可以看到已經停止輸出了。

    下面我們接着來優化這個程式,通過信号和槽來将子線程中的字元串顯示到主界面上。

1.在mythread.h檔案中添加信号的定義:

signals:

void stringchanged(const qstring &amp;);

2.然後到mythread.cpp檔案中更改run()函數的定義:

void mythread::run()

    long int i = 0;

    while (!stopped) {

       qstring str = qstring("in mythread: %1").arg(i);

       emit stringchanged(str);

       msleep(1000);

       i++;

    }

    stopped = false;

這裡每隔1秒就發射一次信号,裡面包含了生成的字元串。

3.到dialog.h檔案中添加槽聲明:

    void changestring(const qstring &amp;);

4.打開dialog.ui,然後向主界面上拖入一個label标簽部件。

5.到dialog.cpp檔案中,在構造函數裡面添加信号和槽的關聯:

// 關聯線程中的信号和本類中的槽

connect(&amp;thread, signal(stringchanged(qstring)),

this, slot(changestring(qstring)));

6.然後添加槽的定義:

void dialog::changestring(const qstring &amp;str)

    ui-&gt;label-&gt;settext(str);

    這裡就是将子線程發送過來的字元串顯示到主界面上。現在可以運作程式,檢視效果了。

(二)線程同步

    qt中的qmutex、qreadwritelock、qsemaphore和qwaitcondition類提供了同步線程的方法。雖然使用線程的思想是多個線程可以盡可能的并發執行,但是總有一些時刻,一些線程必須停止來等待其他線程。例如,如果兩個線程嘗試同時通路相同的全局變量,結果通常是不确定的。qmutex提供了一個互斥鎖(mutex);qreadwritelock即讀-寫鎖;qsemaphore即信号量;qwaitcondition即條件變量。

(三)可重入與線程安全

在檢視qt的幫助文檔時,在很多類的開始都寫着“all functions in this class are reentrant”,或者“all

functions in this class are thread-safe”。在qt文檔中,術語“可重入(reentrant)”和“線程安全(thread-safe)”用來标記類和函數,來表明怎樣在多線程應用程式中使用它們:

一個線程安全的函數可以同時被多個線程調用,即便是這些調用使用了共享資料。因為該共享資料的所有執行個體都被序列化了。

一個可重入的函數也可以同時被多個線程調用,但是隻能是在每個調用使用自己的資料時。

結語

最後要注意的是,使用線程是很容易出現問題的,比如無法在主線程以外的線程中使用gui類的問題(可以簡單的通過這樣的方式來解決:将一些非常耗時的操作放在一個單獨的工作線程中來進行,等該工作線程完成後将結果傳回給主線程,最後由主線程将結果顯示到螢幕上)。大家應該謹慎的使用線程。

涉及到的源碼下載下傳: 

[Qt教程] 第39篇 網絡(九)程式和線程 [Qt教程] 第39篇 網絡(九)程式和線程

kb, 下載下傳次數: 7)