• 沒有找到結果。

資料結構與

N/A
N/A
Protected

Academic year: 2022

Share "資料結構與"

Copied!
15
0
0

加載中.... (立即查看全文)

全文

(1)

C C

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

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

(2)

大綱

 前言

 執行緒( thread )

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

 第一支多執行緒程式

 使用 Event 旗標

 同步化問題( Synchronization )

 使用 Critical Section

(3)

前言

程式 (Program)

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

行程 (Process)

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

執行緒 (Thread)

Process 中一段程式碼的執行序列稱為 Thread ,是作 業系統能夠進行運算與排程的最小單位。

(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

(5)

執行緒與平行處理

 平行程式設計( Parallel Programming )

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

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

CPU0 CPU0 CPU1 CPU1

Process1 Process1

Time

CPU0 CPU0 CPU1 CPU1

Thread1 Thread1 Time

Thread2 Thread2

(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;

(7)

小練習 01

 呈上頁範例,試著使用 getch() 擷取鍵盤的 +, - 鍵,產生一個執行緒的使之可以產生一個時鐘的 計數器。

 參考範例:

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

(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;

}

(9)

使用 Event 旗標

 呈上頁範例,我們發現 main() 的主行程並不會等 待所有的執行緒結束。

 使用 Event 旗標等待 Thread 結束

 (1) 宣告旗標變數

 HANDLE 旗標變數 ;

 (2) 初始化旗標

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

 (3) 設定旗標

 SetEvent( 旗標 );

 (4) 等待信號

Thread 2Thread 2

Thread 1Thread 1

Main processMain process

(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;

}

(11)

小練習 02

 矩陣運算

p11-matrix.cpp 是個可計算 500 x 500 的矩陣運算 程式,試著建立 2~N 個 thread 將它進行平行計算,

並試著估計一下優化的結果。

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

A B C

(12)

執行緒的同步化問題範例

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

(13)

同步化問題( Synchronization )

上一頁的範例,會產生一個 race condition 的問題。

race condition 定義

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

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

Read X = 1 Add X with 1 -

- -

Read X = 1

Process 1 Process 2

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

- - -

Process 1 Process 2

(14)

同步化問題( Synchronization )之解決

要解決 race condition 導致執行緒之間的資料不同步的 問題。通常我們會將執行緒對於記憶體的存取改為

atomic operation

:也就是「將讀取和寫入」某共享 資源的動作,一次性的完成,並且期間不允許其他的行程 打斷。

實作方式:

 (1) 宣告旗標變數

 CRITICAL_SECTION cs;

 (2) 初始化

 InitializeCriticalSection( &cs );

 (3) 將要設定為 atomic operation 的區域設為 critical section

 EnterCriticalSection( &cs );

 // …… atomic operation

(15)

小練習 03

 試著將投影片第 12 頁的範例加上 critical

section ,解決 race condition 的問題。

參考文獻

相關文件

討論結束,整理腦圖。首先嘗試將資料歸類,然 後可以開始收窄範圍,定出文章中心,再按照重

left

1970 年代末期至 1995 年:許多農業生技公司開始投入研發以迄 1995 年第 一個產品上市。Monsanto 為此時期最早的投資者,且為第一個將農業生技產 品上市的公司,其他如 Syngenta 與

利用 BeautifulSoup 將網頁資料以 html.parser 儲存 (

在資本形成方面,因半導體設備比較基數偏高,第1季資本設備

例如:入學申請表格及相關資料,有關文件的範本已上載至教育局 網頁,以供參考。 ( 2022/23

樹、與隨機森林等三種機器學習的分析方法,比較探討模型之預測效果,並獲得以隨機森林

Model-View-Control 架構,資料庫、程式邏輯與呈現完全清楚的分離。在檔 案名稱與目錄結構方面,也都定義的很清楚。資料庫這部份(Active Record) 是