一、多線程是多任務處理的一種特殊形式,多任務處理允許讓電腦同時運行兩個或兩個以上的程序。一般情況下,兩種類型的多任務處理:基於進程和基於線程。基於進程的多任務處理是程序的併發執行。基於線程的多任務處理是同一程序的片段的併發執行。多線程程序包含可以同時運行的兩個或多個部分。這樣的程序中的每個部分稱爲一個線程,每個線程定義了一個單獨的執行路徑,C++ 不包含多線程應用程序的任何內置支持。相反,它完全依賴於操作系統來提供此功能
二、多線程的案例(以下案例都在windows qt 環境下編譯運行)
1. 多線程實現
#include <iostream>
//#include <pthread.h>
#include <time.h>
#include "pthread.h"
using namespace std;
#define NUM_THREADS 5
//c++ 中實現延時函數
void delay(int sec)
{
time_t start_time, cur_time; // 變量聲明
time(&start_time);
do {
time(&cur_time);
} while((cur_time - start_time) < sec );
}
void *say_hello(void *threadid){
//對傳入的參數進行強制類型轉換
int tid = *((unsigned short *)threadid);
cout << "Hello Runoob! 線程ID, "<< tid << endl;
pthread_exit(NULL);
}
int main(){
//定義線程id變量
pthread_t tids[NUM_THREADS];
int indexes[NUM_THREADS];
for(int i = 0;i < NUM_THREADS; ++i){
cout << "main() : 創建線程, " << i << endl;
indexes[i] = i;//先保存i的值
int ret = pthread_create(&tids[i],NULL,say_hello,(void *)&indexes[i]);
if(ret != 0){
cout << "pthread_create error : error_code="<< ret << endl;
}
}
delay(2);
pthread_exit(NULL);
return 0;
}
上述案例使用pthread_create創建線程,參數可以傳入線程入口地址,調用成功後直接進入線程入口函數,入口函數代碼即爲線程體,在線程體執行完畢後調用pthread_exit結束線程,main函數就是一主線程,在其創建的線程都是其子線程,子線程依附於主線程,若主線程提前結束,子線程也會退出,爲了保證子線程能夠正常退出,在main線程中執行了delay 動作保證子線程有足夠的時間調度執行。
執行效果:
main() : 創建線程, 0
main() : 創建線程, 1
Hello Runoob! 線程ID, 0
main() : 創建線程, 2
main() : 創建線程, 3
Hello Runoob! 線程ID, 2
main() : 創建線程, 4
Hello Runoob! 線程ID, 1
Hello Runoob! 線程ID, 3
Hello Runoob! 線程ID, 4
2.線程的分離和鏈接
在任何一個時間點上,線程是可結合的(joinable),或者是分離的(detached)。一個可結合的線程能夠被其他線程收回其資源和殺死;在被其他線程回收之前,它的存儲器資源(如棧)是不釋放的。相反,一個分離的線程是不能被其他線程回收或殺死的,它的存儲器資源在它終止時由系統自動釋放。線程的分離狀態決定一個線程以什麼樣的方式來終止自己。在默認情況下線程是非分離狀態的,這種情況下,原有的線程等待創建的線程結束。只有當pthread_join()函數返回時,創建的線程纔算終止,才能釋放自己佔用的系統資源。而分離線程不是這樣子的,它沒有被其他的線程所等待,自己運行結束了,線程也就終止了,馬上釋放系統資源。程序員應該根據自己的需要,選擇適當的分離狀態。所以如果我們在創建線程時就知道不需要了解線程的終止狀態,則可以pthread_attr_t結構中的detachstate線程屬性,讓線程以分離狀態啓動.
代碼如下:
#include <iostream>
using namespace std;
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
#include <windows.h>
#define NUM_THREADS 5
void *wait(void *t){
int i;
long tid;
tid = (long)t;
Sleep(1000);
cout <<"Sleeping in thread"<< endl;
cout <<"Thread with id: " << tid << "exiting ...!" << endl;
pthread_exit(NULL);
}
int main(){
int rc,i;
pthread_t theads[NUM_THREADS];
pthread_attr_t attr;
void *status;
//初始化並設置線程爲可連接的(joinable)
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
for(i = 0; i < NUM_THREADS ; i ++){
cout << "main() : creating thread: " << i <<endl;
rc = pthread_create(&theads[i],NULL,wait,(void *)i);
if(rc){
cout << "Error:uable to create thread," << endl;
exit(-1);
}
}
//刪除屬性並等待其他線程
pthread_attr_destroy(&attr);
for(i = 0; i < NUM_THREADS; i ++){
rc = pthread_join(theads[i],&status);
if(rc){
cout <<"Uable to join," << endl;
exit(-1);
}
cout << "Main:completed thread id:" << i << endl;
cout << "exiting with status :" << status << endl;
}
cout << "Main: program exiting." << endl;
pthread_exit(NULL);
return 0;
}
案例中先創建線程,然後設置線程的屬性爲joinable,最後回收線程,執行效果如下:
main() : creating thread: 0
main() : creating thread: 1
main() : creating thread: 2
main() : creating thread: 3
main() : creating thread: 4
Sleeping in thread
Thread with id: 1exiting ...!
Sleeping in thread
Thread with id: 3exiting ...!
Sleeping in thread
Thread with id: 0exiting ...!
Sleeping in thread
Thread with id: 2exiting ...!
Sleeping in thread
Thread with id: 4exiting ...!
Main:completed thread id:0
exiting with status :0
Main:completed thread id:1
exiting with status :0
Main:completed thread id:2
exiting with status :0
Main:completed thread id:3
exiting with status :0
Main:completed thread id:4
exiting with status :0
Main: program exiting.
三、移植環境搭建
大家可以注意到,上述的程序都是posix pthread接口即在Linux下使用的api,在win下默認是不能編譯通過,所以編譯之前我們需要做好移植工作,如下:
1.下載windows支持的posix pthread庫,路徑:點擊打開鏈接
2.解壓庫代碼:
解壓pthreads-w32-2-7-0-release .rar到D盤,庫路徑爲D:\Documents\pthreadlib\Pre-built.2\
3.在QT中指定庫的路徑:
LIBS += -LD:\Documents\pthreadlib\Pre-built.2\lib -lpthread