15
資資資資資 C++ 資資資資資資 資資資資multi-thread 資資資資

資料結構與 C++ 程式設計 進階

  • Upload
    aderes

  • View
    119

  • Download
    10

Embed Size (px)

DESCRIPTION

資料結構與 C++ 程式設計 進階. 多執行緒( multi-thread )程式設計. 大綱. 前言 執行緒( thread ) 執行緒與平行程式設計( Parallel Programming ) 第一支多執行緒程式 使用 Event 旗標 同步化問題( Synchronization ) 使用 Critical Section. 前言. 程式 (Program) 儲存於硬碟中的可執行檔稱為 Program 行程 (Process) 載入記憶體中的可執行檔稱為 Process 執行緒 (Thread) - PowerPoint PPT Presentation

Citation preview

Page 1: 資料結構與 C++ 程式設計 進階

資料結構與 C++ 程式設計進階

多執行緒( multi-thread )程式設計

Page 2: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 2

大綱 前言 執行緒( thread ) 執行緒與平行程式設計( Parallel

Programming ) 第一支多執行緒程式 使用 Event 旗標 同步化問題( Synchronization ) 使用 Critical Section

Page 3: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 3

前言 程式 (Program)

儲存於硬碟中的可執行檔稱為 Program

行程 (Process) 載入記憶體中的可執行檔稱為 Process

執行緒 (Thread) Process 中一段程式碼的執行序列稱為 Thread ,是作

業系統能夠進行運算與排程的最小單位。

Page 4: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 4

執行緒( 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

Page 5: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 5

執行緒與平行處理 平行程式設計( Parallel Programming )

將一項任務切成較小、並且可同時處理的子任務,在分配到多核心的處理器上以達到更高的效能。

單一執行緒與多執行緒程式比較

CPU0 CPU1

Process1

Time

CPU0 CPU1

Thread1

Time

Thread2

Page 6: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++

使用 _beginthread() 產生執行緒 _beginthread ( 執行緒要執行的函式 , 堆疊大小 , 變數位址 ) ;

Page 6

第一支執行緒程式

#include <process.h> // thread API#include <stdio.h> #include <windows.h> // Sleep() APIvoid 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;}

Page 7: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 7

小練習 01 呈上頁範例,試著使用 getch() 擷取鍵盤的 +, -

鍵,產生一個執行緒的使之可以產生一個時鐘的計數器。 參考範例:

http://w.csie.org/~r97944012/train/p10-thread-timer.exe

Page 8: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 8

一次產生多個執行緒

#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;}

Page 9: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 9

使用 Event 旗標 呈上頁範例,我們發現 main() 的主行程並不會等

待所有的執行緒結束。 使用 Event 旗標等待 Thread 結束

(1) 宣告旗標變數 HANDLE 旗標變數 ;

(2) 初始化旗標 CreateEvent( 屬性 , 手動旗標 , 初始值 , 名稱 )

(3) 設定旗標 SetEvent( 旗標 );

(4) 等待信號 WaitForSingleObject( 旗標變數 , 等待時間 (ms 或 INFINITE)); WaitForMultipleObjects( 陣列大小 , 旗標變數陣列 , 等待所有旗標 , 等

待時間 )

Thread 2

Thread 1

Main process

Page 10: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 10

等待多個執行緒才終止主行程

#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;}

Page 11: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 11

小練習 02 矩陣運算

p11-matrix.cpp 是個可計算 500 x 500 的矩陣運算程式,試著建立 2~N 個 thread 將它進行平行計算,並試著估計一下優化的結果。

( 提示:若開啟 4 個 thread ,則將 C 矩陣拆成 1/4 運算。 )

A B C

Page 12: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 12

執行緒的同步化問題範例#include <process.h>#include <stdio.h>#define N 10000000int 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;}

Page 13: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 13

同步化問題( Synchronization ) 上一頁的範例,會產生一個 race condition 的問題。 race condition 定義

兩個以上的行程(或執行緒)共用同一資源時,因為共用同一個系統資源,在進行存取時會「因為執行的順序不同,導致結果不一致。」

通常,在多個行程同時進行「寫入」的動作時,才會發生 race condition 。舉例來說,有兩個行程同時想要將記憶體中的 X 變數加上一,有可能發生下列兩種情形:

Read X = 1Add X with 1--Write X = 2-

--Read X = 1Add X with 1-Write X = 2

Process 1 Process 2

Read X = 1Add X with 1Write X = 2---

---Read X = 2Add X with 1Write X = 3

Process 1 Process 2

Page 14: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 14

同步化問題( Synchronization )之解決 要解決 race condition 導致執行緒之間的資料不同步的

問題。通常我們會將執行緒對於記憶體的存取改為atomic operation :也就是「將讀取和寫入」某共享資源的動作,一次性的完成,並且期間不允許其他的行程打斷。

實作方式: (1) 宣告旗標變數

CRITICAL_SECTION cs;

(2) 初始化 InitializeCriticalSection( &cs );

(3) 將要設定為 atomic operation 的區域設為 critical section EnterCriticalSection( &cs ); // …… atomic operation LeaveCriticalSection( &cs );

Page 15: 資料結構與 C++ 程式設計 進階

NTU TRAININGC/C++ Page 15

小練習 03 試著將投影片第 12 頁的範例加上 critical

section ,解決 race condition 的問題。