C C
資料結構與 C++ 程式設計進 階
多執行緒( multi-thread )程式設計
大綱
前言
執行緒( thread )
執行緒與平行程式設計( Parallel Programming )
第一支多執行緒程式
使用 Event 旗標
同步化問題( Synchronization )
使用 Critical Section
前言
程式 (Program)
儲存於硬碟中的可執行檔稱為 Program 行程 (Process)
載入記憶體中的可執行檔稱為 Process 執行緒 (Thread)
Process 中一段程式碼的執行序列稱為 Thread ,是作 業系統能夠進行運算與排程的最小單位。執行緒( thread )
簡介
執行緒( thread )是被包含在行程( Process )中 實際運作的單位。
一個行程中可以並行多個執行緒,而這些執行緒共用同 一份行程的系統資源、名稱位址等等。signal, fd, global var.. etc
Thread 1
Thread 2
Thread 3
Process 1
signal, fd, global var.. etc
Thread 1
Thread 2
Thread 3
Process 2
執行緒與平行處理
平行程式設計( Parallel Programming )
將一項任務切成較小、並且可同時處理的子任務,在分 配到多核心的處理器上以達到更高的效能。 單一執行緒與多執行緒程式比較
CPU0 CPU0 CPU1 CPU1
Process1 Process1
Time
CPU0 CPU0 CPU1 CPU1
Thread1 Thread1 Time
Thread2 Thread2
使用 _beginthread() 產生執行緒
_beginthread ( 執行緒要執行的函式 , 堆疊大小 , 變數位址 ) ;
第一支執行緒程式
#include <process.h> // thread API
#include <stdio.h>
#include <windows.h> // Sleep() API void Thread( void* pParams ) { while(1) {
printf("Thread and Data: %d\n", *(int *)pParams);
Sleep(1000);
} }
int main () { int n = 5;
_beginthread( Thread, 0, &n);
while( 1 ) {
printf("This is main() process.\n");
getchar();
}
return 0;
小練習 01
呈上頁範例,試著使用 getch() 擷取鍵盤的 +, - 鍵,產生一個執行緒的使之可以產生一個時鐘的 計數器。
參考範例:
http://w.csie.org/~r97944012/train/p10-thread-timer.exe
一次產生多個執行緒
#include <process.h>
#include <stdlib.h>
#include <stdio.h>
#define N 20
typedef struct _complex_data {
int iVal;
double fVal;
} cData;
// 重點一、多執行緒
// 重點二、執行緒的資料傳遞方法(傳指標)
void Thread( void* pParams ) { cData *pData = (cData *)pParams;
printf("%d %.2lf\n", pData->iVal, pData->fVal);
使用 _beginthread() 產生執行緒
_beginthread ( 執行緒要執行的函式 , 堆疊大小 , 變數位址 ) ;
int main () { int i;
cData tData[N];
for(i = 0; i < N; i++) { tData[i].iVal = i;
tData[i].fVal = i + 0.5;
_beginthread( Thread, 0, &tData[i]);
}
printf("main()\n");
system("pause");
return 0;
}
使用 Event 旗標
呈上頁範例,我們發現 main() 的主行程並不會等 待所有的執行緒結束。
使用 Event 旗標等待 Thread 結束
(1) 宣告旗標變數
HANDLE 旗標變數 ;
(2) 初始化旗標
CreateEvent( 屬性 , 手動旗標 , 初始值 , 名稱 )
(3) 設定旗標
SetEvent( 旗標 );
(4) 等待信號
Thread 2Thread 2
Thread 1Thread 1
Main processMain process
等待多個執行緒才終止主行程
#include <process.h>
#include <stdlib.h>
#include <windows.h>
#include <stdio.h>
#define N 20
HANDLE hEvent[N];
typedef struct _complex_data {
int tID;
int iVal;
double fVal;
} cData;
void Thread( void* pParams ) { cData *pData = (cData *)pParams;
printf("%d %.2lf\n", pData->iVal, pData->fVal);
SetEvent(hEvent[pData->tID]);
使用 SetEvent() 搭配 WaitForMultipleObjects()int main () { int i;
cData tData[N];
for(i = 0; i < N; i++) {
hEvent[i] = CreateEvent( NULL, FALSE, FALSE, NULL );
tData[i].tID = i;
tData[i].iVal = i;
tData[i].fVal = i + 0.5;
_beginthread( Thread, 0, &tData[i]);
}
WaitForMultipleObjects(N , hEvent, TRUE, INFINITE);
printf("main()\n");
system("pause");
return 0;
}
小練習 02
矩陣運算
p11-matrix.cpp 是個可計算 500 x 500 的矩陣運算 程式,試著建立 2~N 個 thread 將它進行平行計算,並試著估計一下優化的結果。
( 提示:若開啟 4 個 thread ,則將 C 矩陣拆成 1/4 運 算。 )A B C
執行緒的同步化問題範例
#include <process.h>
#include <stdio.h>
#define N 10000000 int x;
void ThreadJob( void* pParams ) { int i;
for ( i = 0; i < N; i++ ) x = x+1;
}
int main () {
_beginthread( ThreadJob, 0, NULL );
_beginthread( ThreadJob, 0, NULL );
while( 1 ) {
printf("x = %d\n", x);
getchar();
}
return 0;