티스토리 뷰
MFC 스레드 동기화
동기화 객체 : 임계영역, 이벤트, 뮤텍스, 세마포어
- API 수준에서 동기화 객체를 다룰때는 종류별로 서로 다른 함수를 사용
- MFC는 이들을 비슷한 방법으로 다룰 수 있도록 클래스 구조와 멤버 함수를 제공하므로 좀더 편히하게 사용할 수 있다.
- 임계 영역
같은 프로세스에 속한 스레드 간의 동기화
커널 모드가 아닌 사용자 모드에서 동작하므로 속도가 빠르다.
서로 다른 프로세스에 속한 스레드 간의 동기화에는 사용 못함.
두 스레드 중 먼저 Lock() 을 호출하는 쪽이 공유 리소스를 잡근할 수 있으며, 나중에 Lock()을 호출하는 쪽은 상대편이 Unlock()을 호출할 때까지 대기하게 된다. (Lock/Unlock 으로 제어)
다이얼로그 베이스 프로젝트를 만든다.
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 |
UINT Thread1(LPVOID pParam)
{
CMFCApplication7Dlg* ptr = (CMFCApplication7Dlg*)pParam;
ptr->m_button1.SetWindowTextW(L"스레드1 시작");
ptr->m_progress1.SetPos(0);
for (int i = 0; i <= 100; i++)
{
ptr->m_progress1.SetPos(i);
::Sleep(10);
}
ptr->m_button1.SetWindowTextW(L"");
return 0;
}
UINT Thread2(LPVOID pParam)
{
CMFCApplication7Dlg* ptr = (CMFCApplication7Dlg*)pParam;
ptr->m_button2.SetWindowTextW(L"스레드2 시작");
ptr->m_progress2.SetPos(0);
for (int i = 0; i <= 100; i++)
{
ptr->m_progress2.SetPos(i);
::Sleep(10);
}
ptr->m_button2.SetWindowTextW(L"");
return 0;
}
class CMFCApplication7Dlg : public CDialogEx
{
...
public:
CButton m_button1;
CButton m_button2;
CProgressCtrl m_progress1;
CProgressCtrl m_progress2;
afx_msg void OnBnClickedStart();
};
BEGIN_MESSAGE_MAP(CMFCApplication7Dlg, CDialogEx)
...
ON_BN_CLICKED(IDC_START, &CMFCApplication7Dlg::OnBnClickedStart)
END_MESSAGE_MAP()
BOOL CMFCApplication7Dlg::OnInitDialog()
{
...
m_progress1.SetRange(0, 100);
m_progress1.SetPos(0);
m_progress2.SetRange(0, 100);
m_progress2.SetPos(0);
return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}
void CMFCApplication7Dlg::OnBnClickedStart()
{
srand((unsigned)time(NULL));
if (rand() % 2 == 0)
{
AfxBeginThread(Thread1, this);
AfxBeginThread(Thread2, this);
}
else
{
AfxBeginThread(Thread2, this);
AfxBeginThread(Thread1, this);
}
} |
cs |
임계영역 적용 전에는 위 그래프와 같이 스레드1과 스레드2 가 동시에 실행된다.
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 |
#include <afxmt.h>
CCriticalSection g_cs; // 전역 변수
UINT Thread1(LPVOID pParam)
{
CMFCApplication7Dlg* ptr = (CMFCApplication7Dlg*)pParam;
ptr->m_button1.SetWindowTextW(L"스레드1 시작");
ptr->m_progress1.SetPos(0);
g_cs.Lock(); // 임계영역 적용
for (int i = 0; i <= 100; i++)
{
ptr->m_progress1.SetPos(i);
::Sleep(10);
}
g_cs.Unlock(); // 임계 영역 해제
ptr->m_button1.SetWindowTextW(L"");
return 0;
}
UINT Thread2(LPVOID pParam)
{
CMFCApplication7Dlg* ptr = (CMFCApplication7Dlg*)pParam;
ptr->m_button2.SetWindowTextW(L"스레드2 시작");
ptr->m_progress2.SetPos(0);
g_cs.Lock();
for (int i = 0; i <= 100; i++)
{
ptr->m_progress2.SetPos(i);
::Sleep(10);
}
g_cs.Unlock();
ptr->m_button2.SetWindowTextW(L"");
return 0;
} |
cs |
나머지 코드는 임계영역 적용 전 코드와 동일 하다.
임계 영역 적용은 1, 2, 8, 14, 24, 30행 코드가 추가된다.
난수 발생시켜 스레드1과 스레드2 중 Lock() 먼저 호출하는 스레드가 먼저 실행되고 Unlock() 되면 다른 스레드가 실행된다.