35.QT-多線程


  程序和進程的區別

  • 進程是動態的,程序是靜態的,進程是程序運行時的實例,是占用系統運行資源的程序
  • 進程是暫時的,程序是永久的, 進程是通過程序運行時得到的
  • 程序是一個數據文件,進程是內存中動態的運行實體,用來存儲數據段,代碼段,指針等,並不占用系統運行資源

程序和進程的關系

  • 一個程序可能對應多個進程,比如當多開某個程序時.
  • 一個進程可能包含多個程序,比如一個程序依賴於包含多個DLL庫(多個程序)


進程和線程的關系

  • 進程是操作系統資源分配的基本單位
  • 線程是操作系統調度執行的基本單位
  • 每個進程包含了1個至多個線程,並且每個線程都可以共享進程的資源
  • 線程也是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.
  • 線程不能脫離進程進行單獨存在,只能依賴於進程進程
  • 在任意線程里都可以創建和撤銷其它的線程
  • 一個線程死掉就等於整個進程死掉,所以多進程的程序要比多線程的程序健壯,缺點在於進程切換時,效率變差

比如,當下載多個文件時,該下載相關的進程就會創建多個線程,每個線程負責下載一個文件


QT中的多線程編程
QT中的線程是以對象的形式(繼承於QThread類)存在的
其中QThread類常用成員函數有:

void run ();
//線程體函數,需要用戶自定義該函數執行的內容,內容里也可以使用exec()實現事件循環
void finished () [signal]
//信號成員函數,表示該線程執行完成,已經在run()函數中return了

void start()[slot]
//啟動函數,將會執行run()函數,並且發射信號started()
void started () [signal]
//信號成員函數,表示該線程已啟動
void terminate() [slot]
//強制結束正在進行的線程(不推薦,因為不會考慮資源釋放), 並且發射信號terminated ()
void quit()
//告訴線程事件循環退出,返回0表示成功,相當於調用了QThread::exit(0)。

void QThread::terminated () [signal]
//信號成員函數,表示該線程已停止
sleep ( unsigned long secs )、msleep()、usleep()、
//休眠當前線程秒,毫秒,微妙

void setPriority(Priority priority);
//設置正在運行的線程優先級,必須在調用start()啟動線程之后設置才有用
bool isFinished() const 
//線程是否結束
bool isRunning() const 
//線程是否正在運行

bool wait ( unsigned long time = ULONG_MAX );
//阻塞等待線程執行結束,如果time(單位毫秒)時間結束,線程還未結束,則返回false,否則返回true,如果time= ULONG_MAX,則表示一直等待

 

多線程示例

class MyThread : public QThread
{
protected:
    void run()
    {
        qDebug()<<this->objectName()<<" priority:"<<this->priority();
      for(int i=0;i<3;i++)
     {
        qDebug()<<this->objectName()<<":"<<i;
        sleep(1);
     }
    }
};
int main(int argc, char *argv[])
{
    QApplication a(argc,argv);
   MyThread t1;
   t1.setObjectName("t1");
   t1.start();
   t1.setPriority(QThread::HighPriority);
   MyThread t2;
   t2.setObjectName("t2");
   t2.start();
   return a.exec();
}

打印:

"t1" priority: 4 
"t1" : 0 
"t2" priority: 7 
"t2" : 0 
"t1" : 1 
"t2" : 1 
"t2" : 2 
"t1" : 2

 由於t1優先級低於t2,所以t2連續打印1和2


多線程-終止示例
在多線程里,一般都是自定義結束函數來結束進程,示例如下:

class Sample : public QThread
{
protected:
    volatile bool m_toStop;

    void run()
    {
        qDebug() << objectName() << " : begin";

        int* p = new int[10000];

        for(int i=0; !m_toStop && (i<10); i++)
        {
            qDebug() << objectName() << " : " << i;

            p[i] = i * i * i;

            msleep(500);
        }

        delete[] p;

        qDebug() << objectName() << " : end";
   }
public:
    Sample()
    {
        m_toStop = false;
    }

    void stop()
    {
        m_toStop = true;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "main begin";

    Sample t;

    t.setObjectName("t");

    t.start();

    for(int i=0; i<100000; i++)
    {
        for(int j=0; j<10000; j++)
        {

        }
    } 
    t.stop(); 
    qDebug() << "main end";
    
    return a.exec();
}

 

多線程的同步
多個線程執行時,有可能某個線程會需要等到另一個線程的結果才能執行,可以通wait()成員函數實現,等待另一個線程完成,如下圖所示:

 


多線程的互斥QMutex
當一個全局的共有資源被多個線程同時調用時,則稱該資源為臨界資源,並且該資源需要使用QMutex互斥類,來保證線程間的互斥,避免同一時刻訪問臨界資源而出現意想不到的問題.
其中QMutex中關鍵成員函數如下:

void lock();
//獲取鎖,如果鎖已經被其它線程獲取,則將會阻塞並While等待鎖釋放
bool tryLock ();
//嘗試獲取鎖, 如果獲得了鎖,該函數返回true,如果另一個線程鎖定了互斥鎖,則該函數立即返回false。
void unlock();
//釋放鎖

示例:

QString g_res="";
QMutex  g_mutex;
class AddThread : public QThread
{
protected:
    void run()
    {
        while(1)
        {
            g_mutex.lock();
            g_res.append("1");
            qDebug()<<"AddThread :"<<g_res;
            g_mutex.unlock();
            msleep(1);
        }
    }
};
class MinusThread : public QThread
{
protected:
    void run()
    {
        while(1)
        {
           g_mutex.lock();
            if(g_res!="")
            {
             g_res.remove(0,1);
             qDebug()<<"MinusThread :"<<g_res;
            }
            g_mutex.unlock();
            msleep(1);
        }
    }
};
int main(int argc, char *argv[])
{
    QApplication a(argc,argv);
    AddThread t1;
    MinusThread t2;
    t1.start();
    t2.start();
    return a.exec();
}

如果有多個不同的臨界資源時,比如: g_res1, g_res2, g_res3...g_resn
則對應的線程鎖也同樣需要分配相同序號: g_mutex1, g_mutex2, g_mute3...g_mutexn
注意:如果多個不同的臨界資源只對應一個線程鎖的話,則會降低並發效率

 

多線程的信號量QSemaphore
信號量是特殊的線程鎖,內部通過一個資源值,來使得N個線程可以同時訪問臨界資源
其中QSemaphore中關鍵成員函數如下:

void acquire ( int n = 1 );
// 試圖獲取由信號量保護的n個資源。如果n是不可用的,這個調用將阻塞,直到有足夠的資源可用為止。
void tryAcquire ( int n = 1 );
//嘗試獲取由信號量保護的n個資源,並在成功時返回true。如果不可用,這個調用立即返回false,並不需要獲得任何資源。
int available () ;
//返回信號量當前可用的資源數量

void release ( int n = 1 );
//釋放由信號量保護的n個資源。

示例:

QSemaphore sem(5); // sem.available() == 5

sem.acquire(3); // sem.available() == 2
sem.acquire(2); // sem.available() == 0
sem.release(5); // sem.available() == 5
sem.release(5); // sem.available() == 10

sem.tryAcquire(1); // sem.available() == 9, returns true
sem.tryAcquire(250); // sem.available() == 9, returns false

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM