일반적으로 두 프로그램 간 동기화 중 가장 간단한 방법은 while문을 통해 A 프로그램에서 전달한 신호가 B 프로그램에서 인식될 때 까지 기다린 후, 원하는 커맨드가 전달되면 프로그램을 실행하는 방법이 있습니다.
그러나 위 방법으로 개발을 진행할 때, A 프로그램에서 커맨드를 전달하는 부분이 많은 경우, 또는 B 프로그램에서 하나의 신호가 아닌, 다중 신호에 대한 처리를 진행할 때, while문에 막혀, 다른 프로세스가 처리되지 않을 수 있습니다.
아래 코드는 B 프로그램에서 while문을 사용했을 때, while문 루틴에 걸려 다른 코드가 실행되지 않음을 경험하고, 별도 Thread와 WaitForSingleObject를 통해 동기화를 처리했던 코드입니다.
1
2
3
4
5
6
7
8
9
// header
static bool g_Sync; // 해제 신호
static int g_CurrentSuspend;
static HANDLE g_ThreadSync;
DWORD WINAPI ThreadSyncronize(LPVOID param);
void WaitFor(int eCmd); // eCmd를 기다린다.
void Resume(int eCmd); // WaitFor 해제
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
// source
#define DEF_SUSPEND_TIMEOUT (20000)
DWORD WINAPI ThreadSyncronize(LPVOID param)
{
// 1. 대기를 시작한 시간을 저장
DWORD dwStart = ::GetTickCount();
while(TRUE)
{
// 20초 이상 기다리는 경우 : Timeout
if(::GetTickCount() - dwStart > DEF_SUSPEND_TIMEOUT)
break;
// 해제 신호가 수신된 경우
if(g_Sync)
break;
}
return (DWORD)TRUE;
}
CCriticalSection g_cs;
void WaitFor(int eCmd)
{
// eCmd는 일종의 Keyword로,
// Resume시 해당 Key가 아닐 경우 동기화가 해제되지 않도록
g_cs.Lock(); // WaitFor을 동시에 호출하는 부분이 많을 경우 필요.
g_CurrentSuspend = eCmd;
g_Sync = false;
if(g_ThreadWait == NULL)
{
DWORD dwResult;
g_ThreadWait = CreateThread(NULL, 0, ThreadSyncronize, NULL, 0, &dwResult);
g_cs.Unlock();
// while문과 같이 해당 부분에서 기다린다.
WaitForSingleObject(g_ThreadWait, INFINITE);
}
else
{
// 1개 이상의 WaitFor 함수가 호출될 경우,
// 이미 CS로 g_ThreadWait은 생성되어 있기 때문에, WaitForSingleObject만 진행
g_cs.Unlock();
WaitForSingleObject(g_ThreadWait, INFINITE);
}
g_cs.Lock();
// Thread 종료.
if(g_ThreadWait != NULL)
{
::TerminateThread(g_ThreadWait, NULL);
CloseHandle(g_ThreadWait);
g_ThreadWait = NULL;
}
g_cs.Unlock();
}
void Resume(int eCmd)
{
// WaitFor에서 지정된 Keyword(eCmd)가 아닐 경우 무시
if(g_CurrentSuspend != eCmd)
return;
g_Sync = true;
}