Create an independent reference to an existing date log handle for concurrent thread access
DuplicateDateLogHandle creates a new DATE_LOG_HANDLE that references the same shared context as the source handle. This enables multiple threads to independently query and cache the last accessed date item without mutex contention. Each duplicated handle maintains its own cache but shares the underlying date collection, providing thread-safe concurrent access with minimal lock contention.
This function is essential for multi-threaded applications that need concurrent read access to the same date collection. Rather than forcing all threads to compete for a single handle's resources, DuplicateDateLogHandle allows each thread to have its own handle with independent caches while sharing the underlying date data.
FreeDateCollectionHandle()
HRESULT _Must_inspect_result_ _Success_(SUCCEEDED(return))DuplicateDateLogHandle(
_In_ DATE_LOG_HANDLE hSourceHandle,
_Out_ DATE_LOG_HANDLE * lpTargetHandle
);
Standard C calling convention with SAL annotations for parameter validation and return value inspection.
[In] DATE_LOG_HANDLE
The source date log handle to duplicate. Creates a new reference to the same underlying context.
InitializeDateLogHandle()[Out] DATE_LOG_HANDLE*
Pointer to receive the newly created duplicate handle on success.
FreeDateCollectionHandle()Duplicate handle created successfully. lpTargetHandle contains the new handle pointer.
Source handle is invalid, corrupted, or being freed by another thread.
lpTargetHandle is NULL.
Insufficient memory to allocate new DATE_LOG structure or mutex.
System error from mutex creation or file duplication. Wrapped as HRESULT.
The duplication process increments the shared context's reference count:
DuplicateDateLogHandle() call: count += 1FreeDateCollectionHandle() call: count -= 1
// Main thread: create and load date log
DATE_LOG_HANDLE hMainDateLog = NULL;
InitializeDateLogHandle(NULL, 0, hHolidays, &hMainDateLog, HandleIsForDatelog);
LoadDateLogHandle(pFile, NULL, NULL, hMainDateLog, NULL, 0);
// Worker threads can now duplicate the handle
for (int i = 0; i < 4; i++) {
DATE_LOG_HANDLE hDuplicate = NULL;
if (SUCCEEDED(DuplicateDateLogHandle(hMainDateLog, &hDuplicate))) {
// Each thread gets its own independent handle
CreateThread(NULL, 0, WorkerThreadProc, hDuplicate, 0, NULL);
}
}
// Worker thread function
DWORD WINAPI WorkerThreadProc(LPVOID lpParam) {
DATE_LOG_HANDLE hDateLog = (DATE_LOG_HANDLE)lpParam;
// Query dates without contending with other threads
for (int i = 0; i < 1000; i++) {
DATE_ITEM_HANDLE hDate = FindDateItemByGuid(hDateLog, &dateId);
}
// Each thread frees its own handle
FreeDateCollectionHandle(hDateLog);
return 0;
FreeDateCollectionHandle(hMainDateLog);
DATE_LOG_HANDLE hOriginal = /* valid handle */;
DATE_LOG_HANDLE hDuplicate = NULL;
HRESULT hr = DuplicateDateLogHandle(hOriginal, &hDuplicate);
if (hr == HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE)) {
printf("Source handle is invalid or being freed\n");
}
else if (hr == HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY)) {
printf("Insufficient memory to create duplicate\n");
}
else if (SUCCEEDED(hr)) {
printf("Duplicate handle created successfully\n");
FreeDateCollectionHandle(hDuplicate);
}
FreeDateCollectionHandle(hOriginal);
ERROR_INVALID_HANDLE is returned.
InitializeDateLogHandle() - Create initial date log handleFreeDateCollectionHandle() - Release handle and decrement reference countFindDateItemByGuid() - Query date items using duplicated handleGetDateCollectionLength() - Query collection size