1 / 15

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

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

aderes
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 資料結構與C++程式設計進階 多執行緒(multi-thread)程式設計

  2. 大綱 • 前言 • 執行緒(thread) • 執行緒與平行程式設計(Parallel Programming) • 第一支多執行緒程式 • 使用Event旗標 • 同步化問題(Synchronization) • 使用Critical Section  Page 2

  3. 前言 • 程式 (Program) • 儲存於硬碟中的可執行檔稱為 Program • 行程 (Process) • 載入記憶體中的可執行檔稱為 Process • 執行緒 (Thread) • Process中一段程式碼的執行序列稱為Thread,是作業系統能夠進行運算與排程的最小單位。  Page 3

  4. 執行緒(thread) • 簡介 • 執行緒(thread)是被包含在行程(Process)中實際運作的單位。 • 一個行程中可以並行多個執行緒,而這些執行緒共用同一份行程的系統資源、名稱位址等等。 Process 2 Process 1 signal, fd, global var.. etc signal, fd, global var.. etc Thread 3 Thread 1 Thread 3 Thread 1 Thread 2 Thread 2  Page 4

  5. 執行緒與平行處理 • 平行程式設計(Parallel Programming) • 將一項任務切成較小、並且可同時處理的子任務,在分配到多核心的處理器上以達到更高的效能。 • 單一執行緒與多執行緒程式比較 Process1 Thread1 Thread2 Time Time CPU0 CPU0 CPU1 CPU1  Page 5

  6. 第一支執行緒程式 • 使用_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; }  Page 6

  7. 小練習01 • 呈上頁範例,試著使用getch()擷取鍵盤的+, -鍵,產生一個執行緒的使之可以產生一個時鐘的計數器。 • 參考範例:http://w.csie.org/~r97944012/train/p10-thread-timer.exe  Page 7

  8. 一次產生多個執行緒 • 使用_beginthread()產生執行緒 • _beginthread (執行緒要執行的函式, 堆疊大小, 變數位址) ; #include <process.h> #include <stdlib.h> #include <stdio.h> #define N 20 typedefstruct _complex_data { intiVal; double fVal; } cData; // 重點一、多執行緒 // 重點二、執行緒的資料傳遞方法(傳指標) void Thread( void* pParams ) { cData *pData = (cData *)pParams; printf("%d %.2lf\n", pData->iVal, pData->fVal); } int main () { inti; cDatatData[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 8

  9. 使用Event旗標 • 呈上頁範例,我們發現main()的主行程並不會等待所有的執行緒結束。 • 使用Event旗標等待Thread結束 • (1) 宣告旗標變數 • HANDLE 旗標變數; • (2) 初始化旗標 • CreateEvent(屬性 , 手動旗標, 初始值, 名稱) • (3) 設定旗標 • SetEvent(旗標); • (4) 等待信號 • WaitForSingleObject(旗標變數, 等待時間(ms或INFINITE)); • WaitForMultipleObjects( 陣列大小 , 旗標變數陣列, 等待所有旗標, 等待時間) Thread 1 Thread 2 Main process  Page 9

  10. 等待多個執行緒才終止主行程 • 使用SetEvent() 搭配WaitForMultipleObjects() #include <process.h> #include <stdlib.h> #include <windows.h> #include <stdio.h> #define N 20 HANDLE hEvent[N]; typedefstruct _complex_data { inttID; intiVal; double fVal; } cData; void Thread( void* pParams ) { cData *pData = (cData *)pParams; printf("%d %.2lf\n", pData->iVal, pData->fVal); SetEvent(hEvent[pData->tID]); } int main () { inti; cDatatData[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 10

  11. 小練習02 • 矩陣運算 • p11-matrix.cpp 是個可計算500 x 500的矩陣運算程式,試著建立2~N個thread將它進行平行計算,並試著估計一下優化的結果。 • (提示:若開啟4個thread,則將C矩陣拆成1/4運算。) A C B  Page 11

  12. 執行緒的同步化問題範例 #include <process.h> #include <stdio.h> #define N 10000000 int x; void ThreadJob( void* pParams ) { inti; 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 12

  13. 同步化問題(Synchronization) • 上一頁的範例,會產生一個race condition的問題。 • race condition定義 • 兩個以上的行程(或執行緒)共用同一資源時,因為共用同一個系統資源,在進行存取時會「因為執行的順序不同,導致結果不一致。」 • 通常,在多個行程同時進行「寫入」的動作時,才會發生race condition。舉例來說,有兩個行程同時想要將記憶體中的X變數加上一,有可能發生下列兩種情形: Process 1 Process 2 Process 1 Process 2 Read X = 1 • Add X with 1 Write X = 2 - - - - - - Read X = 2 Add X with 1 Write X = 3 Read X = 1 • Add X with 1 - - Write X = 2 - - - Read X = 1 Add X with 1 - Write X = 2  Page 13

  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 14

  15. 小練習03 • 試著將投影片第12頁的範例加上critical section,解決race condition的問題。  Page 15

More Related