Vista & Longhorn: 13. InitOnceExecuteOnce API 소개
재미있는 API가 Windows 6.0 버전부터(비스타, 롱혼) 포함되어서 간단하게 소개를 해드릴까 합니다. 사실 ^^ 비스타 관련 API를 몰아서 소개해 드리면 좋겠지만, 저 역시도 이렇게 가끔씩 눈에 띄는 것이 나올 때마다 틈틈이 봐두는 식으로 공부하기 때문에 그럴 수는 없답니다. ^^ (개인적으로 이런 공부 방식을 좋아합니다. 하나씩 하나씩 알아가는.)
소개라고 ^^ 말씀드렸는데요. 그럴 수밖에 없는 것이 이미 코드 구루에 다음와 같은 토픽으로 자세하게 설명되어져 있기 때문입니다.
Simplified One-Time Initialization in Windows Vista
; http://www.codeguru.com/columns/kate/article.php/c13091
위의 토픽을 보시면, 덩달아서 새로운 함수인 "_WriteBarrier"에 대해서도 알게 됩니다. 일단, 제가 파악해 본 바에 의하면, 최적화가 컴파일 타임에도 발생하지만 64bit 환경에서는 프로세서에 의해서도 발생을 한다고 합니다. 컴파일 타임에 대한 최적화 방지 예제는 "_WriteBarrier" API 도움말 자체에 코드가 같이 설명되어져 있습니다.
C++ Language Reference - _WriteBarrier
; https://learn.microsoft.com/en-us/cpp/intrinsics/writebarrier
프로세서에 의한 최적화 예제 코드는 "Simplified One-Time Initialization in Windows Vista"에 나와 있는 것이 그에 해당합니다. 재미있으니 한번 코드를 살펴보십시오. ^^
이번 이야기의 주제는 "Vista's One-Time Initialization Support"이니, 그에 대해 조금 더 살펴보겠습니다. 보통, 동기화 코드 중에는 다음과 같은 식으로 초기화를 해야 하는 코드가 빈번하게 발생하는데요.
if (g_p == NULL)
{
EnterCriticalSection(&G_CriticalSection);
if (g_p == NULL)
{
g_p = new ExpensiveToCreateClass();
}
LeaveCriticalSection(&G_CriticalSection);
}
return g_p;
보시는 것처럼, 다소 쓸데없는 듯이 2번의 NULL 검사(double-check code)를 해야 합니다. 음... 그러고 보니 이러한 패턴을 어디선가 본 것 같은 기억이 납니다. 그렇군요. ^^ 다음의 토픽에서 재미있게 읽었었지요.
Loner's .NET Blog - Quiz: Synchronization Bug
; http://www.simpleisbest.net/archive/2006/09/21/1103.aspx
Loner's .NET Blog - Answer: Synchronization Tip
; http://www.simpleisbest.net/archive/2006/09/27/1125.aspx
자,,, 이러한 패턴을 비스타에서는 InitOnceBeginInitialize API를 사용하여 다음과 같이 수정할 수 있습니다.
INIT_ONCE g_init;
BOOL CALLBACK CreateETCCPointer(PINIT_ONCE InitOnce, PVOID Parameter,
PVOID *lpContext)
{
*lpContext = new ExpensiveToCreateClass();
return TRUE;
}
PVOID lpContext;
if (InitOnceExecuteOnce(&g_init,
CreateETCCPointer,
NULL, &lpContext)){
return (ExpensiveToCreateClass*)lpContext;
}
왠지... ^^; 더 간결해 보이지는 않는군요. 또한 아직 Managed 래퍼 코드는 없는 듯 하니 C# 등에서 사용하기에는 좀 더 기다려야 될 것 같습니다.
마지막으로, InitOnceExecuteOnce API는 비동기 함수 버전을 제공해 주는 데, "InitOnceBeginInitialize" / "InitOnceComplete" 쌍의 함수가 그것입니다. Native API라서 InitOnceExecuteOnce 함수 자체도 그다지 쓸 일이 없을 것 같은데... ^^ 그에 대한 비동기 함수는 더더욱 잘 안 쓰겠지요!
InitOnceExecuteOnce
; https://learn.microsoft.com/ko-kr/windows/win32/api/synchapi/nf-synchapi-initonceexecuteonce
define _WIN32_WINNT as 0x0600 or later
Client Requires Windows Vista.
Server Requires Windows Server "Longhorn".
Header Declared in Winbase.h; include Windows.h.
Library Use Kernel32.lib.
RtlRunOnceExecuteOnce (DDK)
; https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-rtlrunonceexecuteonce
[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]