[windowsAPI] 13주차, Thread(2) 멀티스레드까지 경험하기

교내 전공과목인 윈도우즈 API수업을 정리합니다

 

 

 

1. Rand-Key-BackGround, 스레드로 구현하기

기본적으로 바탕에서 랜덤색상의 점찍기가 진행된다 // ThreadFumc

그리고 사용자가 동적으로 키이벤트(문구 작성), 마우스이벤트(큰 점 찍기)를 일으킬 수 있게한다 // WndProc

(1) 소스코드

 /*필요한 변수 */
HWND hWndMain; //주 핸들
TCHAR str[256]; //문자 출력할 공간


/* 스레드함수 */
DWORD WINAPI ThreadFunc(LPVOID temp){
	HDC hdc = GetDC(hWndMain);
	for (;;){
		SetPixel(hdc, rand() % 500, rand()% 400,  //랜덤 위치에
			RGB(rand() % 256, rand() % 256, rand() % 256)); //랜덤 색상으로
	}
	ReleaseDC(hWndMain, hdc);
	return 0;
}


/* 윈프록 내부 */
	HDC hdc;
	PAINTSTRUCT ps; //문자
	int i, len; //문자 담기
    DWORD ThreadID;
	HANDLE hThread;
    
   switch (iMessage){
		/* 키 입력 받기 */
	case WM_CHAR:
		len = lstrlen(str);
		str[len] = (TCHAR)wParam;
		str[len + 1] = 0;
		InvalidateRect(hWnd, NULL, FALSE);
		return 0;

	case WM_CREATE:
		hWndMain = hWnd;
		hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID);
		CloseHandle(hThread);
		return 0;

		/* 점 찍기 */
	case WM_LBUTTONDOWN:
		hdc = GetDC(hWnd);
		Ellipse(hdc, LOWORD(lParam) - 10, HIWORD(lParam) - 10, LOWORD(lParam) + 10, HIWORD(lParam) + 10);
		ReleaseDC(hWnd, hdc);
		return 0;

		/* 입력된 문자 출력 */
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		TextOut(hdc, 100, 100, str, lstrlen(str));
		EndPaint(hWnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd, iMessage, wParam, lParam));

(2) 실행결과

안 예뻐.

 

2. Rand-Key-BackGround2, 문자 카운트 기능 추가하기

백그라운드의 자동 점찍기는 제거하고, 점찍기도 가능하면서

키 입력때마다 문장의 a개수를 세는 기능을 추가하자

(1) 소스코드

 /* 변수는 이전처럼 그대로 쓰고 있음 */
 HWND hWndMain;
TCHAR str[256]; //입력할 문구 공간

/* '카운트 및 카운트 출력' 스레드, 원래는 백그라운드 점찍기기능 */
DWORD WINAPI ThreadFunc(LPVOID temp){
	int iCount;
	TCHAR buf[256];
	HDC hdc = GetDC(hWndMain);

	// a에 대하여 카운트 시키기
	iCount = 0;
	for (int i = 0; i < lstrlen(str); i++){
		if (str[i] == TCHAR('a')) iCount++;
		Sleep(10); //Complex BackGorund Job (네?) 
	}

	// 카운트 한 내용 출력
	wsprintf(buf, TEXT("%c의 개수 : %d"), TCHAR('a'), iCount);
	TextOut(hdc, 10, 10, buf, lstrlen(buf));

	ReleaseDC(hWndMain, hdc);
	return 0;
}


/* 윈프록 > switch > case WM_CHAR */
	case WM_CHAR:
		len = lstrlen(str);
		str[len] = (TCHAR)wParam;
		str[len + 1] = 0;

		/* 키 입력 발생 시 스레드 작동*/
		hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID); 
		InvalidateRect(hWnd, NULL, FALSE);
		return 0;
        
/* 윈프록 > switch > case WM_CREATE */
	case WM_CREATE:
		hWndMain = hWnd;
		//CloseHandle(hThread);
		return 0;

(2) 실행결과

안 예뻐.

 

1. Rand-Key-BackGround2, 멀티스레드 적용하기

인자전달을 통해 A,B,C,D 각각을 세는 스레드를 만들자

 

(0) 우선, 포인터를 다시 정리해보자

int *a, *b, c = 6, d; //메모리 잡음
a = &c;
b = &d;
*b = *a // 왼측: 위치, 오른쪽: 값,  => b가 가리키는 위치에 a가 가리키는 값을 넣겠다.
int *a *b, c = 6, d;
a=&c 
b=%d; 

/* 까지 진행했을 때는 다음과 같음 */
주소 1000 [ ] d   // 1000번 자리에 빈 값을 d가 차지한다
주소 1004 [6] c   // 1004번 자리에 6값을 c가 차지한다
주소 1008 [주소 1000] b   //1008번 자리에 주소1000을 가리키는 b가 있다
주소 1012 [주소 1004] a   // 1012번 자리에 주소1004를 가리키는 a가 있다

*b = &a

/*위 코드까지 진행했을 때는 다음과 같음 */
주소 1000 [5] d  // 2)  b가 가리킨 1000(d)자리에 a가 가리킨 값(c=5)을 넣는다
주소 1004 [5] c
주소 1008 [주소1000] b      // 1)b는 주소 1000(d)을 가리키고
주소 1012 [주소1004] a

 

 

(1) 소스코드

 //스레드로 넘길 인수 구조체 추가
struct Threadparam {
	int x, y;
	TCHAR ch;
} Param[4] = {
	{ 10, 10, TCHAR('a') },
	{ 10, 30, TCHAR('b') },
	{ 10, 50, TCHAR('c') },
	{ 10, 70, TCHAR('d') }
};


DWORD WINAPI ThreadFunc(LPVOID temp) {
	int iCount = 0;
	TCHAR buf[256];
	HDC hdc = GetDC(hWndMain);

	/* 각 문자에 대하여 문자 수 카운팅 */
	Threadparam* tp = (Threadparam*)temp; 
	for (int i = 0; i < lstrlen(str); i++){
		if (str[i] == tp->ch) iCount++;
		Sleep(10);
	}

	wsprintf(buf, TEXT("%c의 개수 ; %d"), tp->ch, iCount);
	TextOut(hdc, tp->x, tp->y, buf, lstrlen(buf));

	ReleaseDC(hWndMain, hdc);
	return 0;
}


/* 윈프록 > WM_CHAR */
	case WM_CHAR:
		len = lstrlen(str);
		str[len] = (TCHAR)wParam;
		str[len + 1] = 0;

		//한 번 입력 > 문자 각각에 대한 스레드 발생
		for (i = 0; i < 4; i++){
			CloseHandle(CreateThread(NULL, 0, ThreadFunc, &Param[i], 0, &ThreadID));
		}

		InvalidateRect(hWnd, NULL, FALSE);
		return 0;
   	case WM_CREATE:
		hWndMain = hWnd;
		return 0;

(2) 실행결과

 

그러나 문제가 있다. WM_CHAR케이스에 넣어놨으니, 키를 누를 때마다 스레드를 생성하는 비효율적인 작업이 일어난다