티스토리 뷰
신호(Signaled) 와 비신호(Nonsignaled) 2개 상태를 가진 동기화 객체
- 이벤트 동기화 방법
1. 이벤트 객체를 비신호 상태로 생성
2. 하나의 스레드가 초기화 작업을 진행하고, 나머지 스레드는 이벤트 객체데 대해 Lock()을 호출함으로써 이벤트 객체가 신호 상태가 되기를 기다린다. (Sleep 상태)
3. 스레드가 초기화 작업을 완료하면, 이벤트 객체를 신호 상태로 바꾼다.
4. 기다리고 있던 모든 스레드가 깨어나서 작업을 진행한다.
- 이벤트 특성에 따른 두 종류
1. 자동 리셋(Auto Reset)
이벤트 객체를 신호 상태로 바꾸면, 기다리는 스레드 중 하나만 깨운 후 자동으로 비신호 상태가 된다. 산호 상태에서 비신호 상태로 되는것을 리셋(Reset)이라 부른다.
2. 수동 리셋(Manual Reset)
이벤트 객체를 신호 상태로 바꾸면, 계속 신호 상태를 유지한다. 결과적으로 기다리는 스레드를 모두 깨우게 된다. 리셋으 ㄹ하려면 명시적으로 함수를 호출해야 한다.
- 이벤트 생성 함수
CEvent::CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);
- bInitiallyOwn
FALSE 면 비신호, TRUE 면 신호 상태
- bManualReset
FALSE 면 자동 리셋, TRUE 면 수도 ㅇ리셋 이벤트가 된다.
- lpszName
이벤트 이름, NULL을 지정하면 이름없는(Anonymouse) 이벤트가 된다. 서로다른 프로세스에 존재하는 스레드가 이벤트를 이용하여 스레드 동기화를 하려면 동일한 이름을 가진 이벤트를 접근해야 한다.
-lpsaAttribute
핸들 상속에 관련된 구조체로 특별한 경우가 아니면 NULL 값을 사용한다.
- 이벤트의 상태를 바꾸는 함수
BOOL CEvent::SetEvent();
신호 상태를 바꾼다.
BOOL CEvent::ResetEvent();
이벤트 객체를 비신호 상태로 바꾼다. 자동 리셋 이벤트에 대해서는 이 함수를 사용할 필요가 없다.
BOOL CEvent::PulseEvent();
이벤트 객체를 신호 상태로 바꾸고, 신호 상태를 기다리는 다른 스레드를 깨운 후 다시 비신호 상태로 바꾼다. 자동 리셋 이벤트일 경우에는 하나의 스레드만 깨우며, 수동 리셋 이벤트일 경우에는 기다리는 모든 스레드를 깨운다.
<임계영역, 뮤텍스와 차이점>
2개 이상의 스레드가 공유 리소스를 사용하는 경우 - 임계영역, 뮤텍스를 사용
1개의 스레드가 작업을 완료한 후 기다리고 있던 다른 모든 스레드에게 알려주는 경우 - 이벤트를 사용
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 |
UINT InitThread(LPVOID pParam)
{
CProgressCtrl* ptr = (CProgressCtrl*)pParam;
ptr->SetPos(0);
for (int i = 0; i < 100; i++)
{
ptr->SetPos(i);
::Sleep(10);
}
return 0;
}
UINT WorkThread(LPVOID pParam)
{
CProgressCtrl* ptr = (CProgressCtrl*)pParam;
ptr->SetPos(0);
for (int i = 0; i < 100; i++)
{
ptr->SetPos(i);
::Sleep(10);
}
return 0;
}
void CMFCApplication7Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PROGRESS1, m_progress1);
DDX_Control(pDX, IDC_PROGRESS3, m_progress3);
DDX_Control(pDX, IDC_PROGRESS4, m_progress4);
DDX_Control(pDX, IDC_PROGRESS5, m_progress5);
DDX_Control(pDX, IDC_PROGRESS6, m_progress6);
DDX_Control(pDX, IDC_PROGRESS2, m_progress2);
}
BEGIN_MESSAGE_MAP(CMFCApplication7Dlg, CDialogEx)
...
ON_BN_CLICKED(IDC_START, &CMFCApplication7Dlg::OnBnClickedStart)
END_MESSAGE_MAP()
void CMFCApplication7Dlg::OnBnClickedStart()
{
AfxBeginThread(InitThread, &m_progress1);
AfxBeginThread(WorkThread, &m_progress2);
AfxBeginThread(WorkThread, &m_progress3);
AfxBeginThread(WorkThread, &m_progress4);
AfxBeginThread(WorkThread, &m_progress5);
AfxBeginThread(WorkThread, &m_progress6);
} |
cs |
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 |
#include <afxmt.h>
CEvent g_event(FALSE, TRUE); // 전역 변수
UINT InitThread(LPVOID pParam)
{
CProgressCtrl* ptr = (CProgressCtrl*)pParam;
ptr->SetPos(0);
for (int i = 0; i < 100; i++)
{
ptr->SetPos(i);
::Sleep(10);
}
g_event.PulseEvent();
return 0;
}
UINT WorkThread(LPVOID pParam)
{
CProgressCtrl* ptr = (CProgressCtrl*)pParam;
ptr->SetPos(0);
g_event.Lock();
for (int i = 0; i < 100; i++)
{
ptr->SetPos(i);
::Sleep(10);
}
return 0;
} |
cs |
이벤트 적용 후 InitThread 스레드 진행 후 다른 모든 스레드를 깨운다.