程式和進程的區別 進程是動態的,程式是靜態的 進程是暫時的,程式是永久的, 進程是通過程式運行時得到的 程式是一個數據文件,進程是記憶體中動態的運行實體,用來存儲數據段,代碼段,指針等 程式和進程的關係 一個程式可能對應多個進程 一個進程可能包含多個程式,比如一個程式依賴多個其它動態庫時 進程和線程的 ...
程式和進程的區別
- 進程是動態的,程式是靜態的
- 進程是暫時的,程式是永久的, 進程是通過程式運行時得到的
- 程式是一個數據文件,進程是記憶體中動態的運行實體,用來存儲數據段,代碼段,指針等
程式和進程的關係
- 一個程式可能對應多個進程
- 一個進程可能包含多個程式,比如一個程式依賴多個其它動態庫時
進程和線程的關係
- 進程是操作系統資源分配的基本單位
- 線程是操作系統調度執行的基本單位
- 每個進程包含了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
多線程-終止示例
在多線程里,一般都是自定義結束函數來結束進程,示例如下:
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