UI 스레드

 

스레드는 보통 백그라운드에서 작업을 하며 사용자 눈에는 보이지 않는다. 이처럼 내부적인 계산만 하고 조용히 사라지는

스레드를 작업 스레드(Word Thread)라고 하는데 대부분의 스레드는 작업 스레드이다.

 

UI 스레드는 윈도우를 만들고 메시지 큐와 메시지 루프를 가진다. 메시지 큐는 스레드별로 생성되는데 UI 스레드는

주 스레드와는 다른 메시지 큐를 가지는 스레드이다. 윈도우를 가지고 메시지를 처리할 수 있다는 말은 곧 사용자와

상호 작용을 할 수 있다는 뜻이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include <Windows.h>
 
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass="ThreadStopResume";
DWORD WINAPI ThreadFunc(LPVOID temp);
LRESULT CALLBACK DeCompProc(HWND hWnd, UINT iMessage,WPARAM wParam, LPARAM lParam);
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam,int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst=hInstance;
 
    WndClass.cbClsExtra=0;
    WndClass.cbWndExtra=0;
    WndClass.hbrBackground=(HBRUSH)(COLOR_WINDOW + 1);
    WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    WndClass.hInstance=hInstance;
    WndClass.lpfnWndProc=(WNDPROC)WndProc;
    WndClass.lpszClassName=lpszClass;
    WndClass.lpszMenuName=NULL;
    WndClass.style=CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = g_hInst;
    WndClass.lpfnWndProc = DeCompProc;
    WndClass.lpszClassName = "DecompWnd";
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,
        CW_USEDEFAULT,CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);
    ShowWindow(hWnd,nCmdShow);
    hWndMain = hWnd;
 
    while(GetMessage(&Message,0,0,0)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
    return Message.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    TCHAR* Mes = "왼쪽 버튼을 누르면 압축 해제 스레드를 실행합니다.";
    HANDLE hThread;
    DWORD ThreadID;
 
    switch(iMessage) 
    {
    case WM_LBUTTONDOWN:
        hThread = CreateThread(NULL0, ThreadFunc, NULL0&ThreadID);
        CloseHandle(hThread);
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        TextOut(hdc, 1010, Mes, lstrlen(Mes));
        EndPaint(hWnd, &ps);
        return 0;    
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
 
DWORD WINAPI ThreadFunc(LPVOID temp)
{
    HWND hWnd;
    MSG Message;
 
    hWnd = CreateWindow("DecompWnd""압축 해제 중", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
        400150, hWndMain, (HMENU)NULL, g_hInst, NULL);
    ShowWindow(hWnd, SW_SHOW);
 
    while(GetMessage(&Message, NULL00)){
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
 
    return Message.wParam;
}
 
LRESULT CALLBACK DeCompProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    TCHAR Cap[256];
    int Value;
 
    switch(iMessage)
    {
    case WM_CREATE:
        CreateWindow("button""시작", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 50809025, hWnd,(HMENU)0, g_hInst, NULL);
        CreateWindow("button""닫기", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 250809025, hWnd,(HMENU)1, g_hInst, NULL);
        Value = 0;
        SetProp(hWnd, "VALUE", (HANDLE)Value);
        SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(0, BN_CLICKED), (LPARAM)0);
        return 0;
    case WM_TIMER:
        Value = (int)GetProp(hWnd, "VALUE");
 
        //실제 압축 코드가 있다면 Timer가 아닌 압축을 진행하는 코드를 넣으면된다.
 
        Value++;
        wsprintf(Cap, "압축 해제 중 : %d", Value);
        SetWindowText(hWnd, Cap);
        SetProp(hWnd, "VALUE",(HANDLE)Value);
        if (Value == 100) {
            SetWindowText(hWnd, "압축 해제 완료");
            KillTimer(hWnd, 1);
            EnableWindow(GetDlgItem(hWnd,0), FALSE);
        }
        return 0;
    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case 0:
            GetDlgItemText(hWnd, 0, Cap, 256);
            if (lstrcmp(Cap, "시작"== 0) {
                SetDlgItemText(hWnd,0,"중지");
                SetTimer(hWnd,1,200,NULL);
            }else{
                SetDlgItemText(hWnd,0,"시작");
                KillTimer(hWnd,1);
            }
            break;
        case 1:
            DestroyWindow(hWnd);
            break;
        }
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
 
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs

 

ThreadFunc에서는 압축 해제 경과를 표시하는 윈도우를 만들고 메시지 루프를 돌리는데 WinMain과 흡사하다.

또한, 윈도우 클래스는 스레드 별로 중복 등록할 필요가 없으므로 WinMain에서 딱 한 번만 등록한다.

 

UI 스레드(Threadfunc)는 메시지 큐를 따로 가지는데 운영체제는 윈도우를 생성하는 스레드에 대해 별도의 메시지 큐를

생성한다. DeCompProc는 전달되는 메시지를 처리하며 압축 해제 작업을 시뮬레이션한다.

 

닫기 버튼을 누르면 DestroyWindow 함수를 호출하여 WM_DESTROY Message를 전달받고 PostQuitMessage를 호출하여

스레드의 메시지 루프를 종료시켜 스레드 자체를 종료한다.

 

 

'Programming > Thread' 카테고리의 다른 글

[API] Thread 6 (동기화 - 크리티컬 섹션)  (0) 2017.08.30
[API] Thread 5 (스케줄링)  (0) 2017.08.30
[API] Thread 3 (Thread 관리)  (0) 2017.08.29
[API] Thread 2 (MultiThread)  (0) 2017.08.29
[API] Thread 1 (단일 Thread)  (0) 2017.08.24

+ Recent posts