How do I get the SRWLock mechanism to work.

Joseph RW 85 Reputation points
2025-08-27T06:10:29.5033333+00:00

What I am trying to do is download a file and after each 4096 Bytes print the Download Progress from the ReadSharedData() thread using a global_shared_data, to prevent Data Race conditions I am using the SRWLock mechanism but the program just prints Downloading http://127.0.0.1:8000/a-guide-to-kernel-exploitation.pdf to downloaded_file.pdf... and freezes there, what am I doing wrong.

#include <windows.h>
#include <wininet.h>
#include <wchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#pragma comment(lib, "wininet.lib")

HANDLE g_fileHandle;
HINTERNET g_hUrl;
HINTERNET g_hInternet;
WCHAR g_status[] = L"START";

// Shared resource
DWORD global_shared_data = 0;
SRWLOCK g_srw_lock; // Declare the SRW lock globally
struct ForCreateThread {
    HANDLE handle_to_file;
    HINTERNET hUrl;
    HINTERNET hInternet;
    //const char* url;
    //const char* outputPath;
};

// A function that reads the shared data
DWORD WINAPI ReadSharedData() {
    // Acquire the lock for shared access
    // No need to initialize here if already done by the main thread
    ::AcquireSRWLockShared(&g_srw_lock);
    while (g_status == L"COMPLETE") {
        // Shared section: Multiple threads can be here at the same time
        std::cout << "Thread " << GetCurrentThreadId() << " read shared_data as " << global_shared_data << std::endl;
        // Release the lock
        ::ReleaseSRWLockShared(&g_srw_lock);
        ::Sleep(15000);
    }
    return 42;
}

DWORD WINAPI DownloadFile(LPVOID lpParam) {
  
    //::InitializeSRWLock(&g_srw_lock); // Initialize only once in a real application
  
    ForCreateThread* params = static_cast<ForCreateThread*>(lpParam);
    HINTERNET hInternet = params->hInternet;
    HINTERNET hUrl = params->hUrl;
  
    BOOL success = FALSE;
    DWORD bytesRead = 0;
    BYTE buffer[4096];
    DWORD bytesWritten = 0;
    HANDLE hFile = params->handle_to_file;

        // Read data from URL and write to file
    while (::InternetReadFile(hUrl, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
        if (!::WriteFile(g_fileHandle, buffer, bytesRead, &global_shared_data, NULL)) {
            printf("WriteFile failed: %lu\n", GetLastError());
            //goto cleanup;
        }
        ::AcquireSRWLockExclusive(&g_srw_lock);
        printf("Downloaded %lu bytes...\r\n", global_shared_data);
        printf("ThreadID %lu\n", GetCurrentThreadId());
        // Release the lock
      
        ::ReleaseSRWLockExclusive(&g_srw_lock);
        ::Sleep(10000);
    }
  
    printf("\nDownload completed successfully!\n");
    wcscpy_s(g_status, L"COMPLETE");
    return 42;
}
int main() {
    ::InitializeSRWLock(&g_srw_lock); // Initialize only once in a real application
    const char* url = "http://127.0.0.1:8000/a-guide-to-kernel-exploitation.pdf";
    const char* outputPath = "downloaded_file.pdf";
    BOOL success = FALSE;
    DWORD bytesRead = 0;
    BYTE buffer[4096];
    DWORD bytesWritten = 0;
        // Initialize WinINet
    g_hInternet = ::InternetOpenA("WinINet Downloader/1.0",
        INTERNET_OPEN_TYPE_PRECONFIG,
        NULL, NULL, 0);
    if (!g_hInternet) {
        printf("InternetOpenA failed: %lu\n", GetLastError());
        //goto cleanup;
    }
    // Open URL
    g_hUrl = ::InternetOpenUrlA(g_hInternet, url, NULL, 0,
        INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0);
    if (!g_hUrl) {
        printf("InternetOpenUrlA failed: %lu\n", GetLastError());
        //goto cleanup;
    }
    // Create output file
    g_fileHandle = ::CreateFile(
        L"downloaded_file.pdf",
        GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );//https://stackoverflow.com/questions/1576187/can-createfile-open-one-file-at-the-same-time-in-two-different-thread
    if (g_fileHandle == INVALID_HANDLE_VALUE) {
        printf("CreateFileA failed: %lu\n", GetLastError());
        //goto cleanup;
        return 1;
    }
    printf("Downloading %s to %s...\n", url, outputPath);
    ForCreateThread* params = new ForCreateThread();
    params->handle_to_file = g_fileHandle;
    //params->url = "http://127.0.0.1:8000/a-guide-to-kernel-exploitation.pdf";
    //params->outputPath = "a-guide-to-kernel-exploitation.pdf";
    params->hUrl = g_hUrl;
    params->hInternet = g_hInternet;
    HANDLE hThread[2];
    hThread[0] = CreateThread(
        NULL,                   // Default security attributes
        0,                      // Default stack size
        (LPTHREAD_START_ROUTINE)DownloadFile, // Thread function
        (LPVOID)params,         // Pointer to the parameters structure
        0,                      // Default creation flags
        NULL                    // Don't need thread ID
    );
    hThread[1] = CreateThread(
        NULL,                   // Default security attributes
        0,                      // Default stack size
        (LPTHREAD_START_ROUTINE)ReadSharedData, // Thread function
        NULL,         // Pointer to the parameters structure
        0,                      // Default creation flags
        NULL                    // Don't need thread ID
    );
  
    /*
    if (DownloadFile(url, outputPath)) {
        printf("File downloaded successfully!\n");
    }
    else {
        printf("Download failed!\n");
        return 1;
    }
    */
    // Wait for all three threads to finish
    WaitForMultipleObjects(
        2, // number of objects in the array
        hThread, // array of object handles
        TRUE, // bWaitAll: TRUE to wait for all objects to be signaled
        INFINITE // dwMilliseconds: INFINITE to wait indefinitely
    );
    ::CloseHandle(hThread[0]);
    ::CloseHandle(hThread[1]);
    return 0;
}

User's image

Developer technologies | C++
0 comments No comments
{count} votes

Accepted answer
  1. RLWA32 50,496 Reputation points
    2025-08-27T08:48:28.8933333+00:00

    The posted code has a couple of obvious problems.

    WCHAR g_status[] = L"START";
    

    The CRT will have a problem with the buffer overflow created by -

        wcscpy_s(g_status, L"COMPLETE");
    

    assuming execution ever reaches that point.

    The comparison in ReadSharedData -

        while (g_status == L"COMPLETE") 
    

    is improper. It won't be true. Use the crt functions for string comparison.

    If the reader thread acquires the lock first, the writer will be starved because the reader exits without releasing the lock.

    Doesn't the writer thread call WriteFile using the g_shared_data before acquiring a lock?

    I suggest you fix the coding problems and then run the code under the Application Verifier.

    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Joseph RW 85 Reputation points
    2025-08-27T11:46:21.2433333+00:00

    I have it working, thanks @RLWA32 , but it seems *SRWLockShared functions failed and only the *SRWLockExclusive worked as intended.

    User's image

    // thread_sync_exercise.cpp : This file contains the 'main' function. Program execution begins and ends there.
    //
    #include <windows.h>
    #include <wininet.h>
    #include <wchar.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    
    #pragma comment(lib, "wininet.lib")
    
    HANDLE g_fileHandle;
    HINTERNET g_hUrl;
    HINTERNET g_hInternet;
    WCHAR g_status[] = L"START";
    
    // Shared resource
    uint64_t global_shared_data = 0;
    SRWLOCK g_srw_lock; // Declare the SRW lock globally
    
    struct ForCreateThread {
        HANDLE handle_to_file;
        HINTERNET hUrl;
        HINTERNET hInternet;
        //const char* url;
        //const char* outputPath;
    };
    
    // A function that reads the shared data
    DWORD WINAPI ReadSharedData() {
        // Acquire the lock for shared access
        // No need to initialize here if already done by the main thread
        
    
        while (wcscmp(g_status, L"COMPLETE") != 0) {
        //while (TRUE) {
    
            if (::TryAcquireSRWLockExclusive(&g_srw_lock)) {
                //printf("ReadSharedData Acquired\n");
                ::AcquireSRWLockExclusive(&g_srw_lock);
            }
            else {
                //printf("ReadSharedData failed to acquire\n");
            }
    
            
            
            // Shared section: Multiple threads can be here at the same time
            std::cout << "Thread ID: " << GetCurrentThreadId() << " Total Bytes Downloaded:  " << global_shared_data << " (Print Process)\n" << std::endl;
    
            // Release the lock
            ::ReleaseSRWLockExclusive(&g_srw_lock);
            ::Sleep(15000);
        }
        return 42;
    }
    
    
    DWORD WINAPI DownloadFile(LPVOID lpParam) {
        
      
        ForCreateThread* params = static_cast<ForCreateThread*>(lpParam);
        HINTERNET hInternet = params->hInternet;
        HINTERNET hUrl = params->hUrl;
    
        
        BOOL success = FALSE;
        DWORD bytesRead = 0;
        BYTE buffer[4096];
        DWORD bytesWritten = 0;
    
        HANDLE hFile = params->handle_to_file;
        //const char* outputPath = params->outputPath;
        //const char* url = params->url;
    
    
        // Read data from URL and write to file
        while (::InternetReadFile(hUrl, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
            if (!::WriteFile(g_fileHandle, buffer, bytesRead, &bytesWritten, NULL)) {
                printf("WriteFile failed: %lu\n", GetLastError());
                //goto cleanup;
            }
    
            if (::TryAcquireSRWLockExclusive(&g_srw_lock)) {
                //printf("DownloadFile acquired\n");
                ::AcquireSRWLockExclusive(&g_srw_lock);
            }
            else {
               // printf("DownloadFile Failed to acquire\n");
            }
    
            
            global_shared_data = global_shared_data + (uint64_t)bytesWritten;
            printf("Thread ID:  %lu (Download Process)\n", GetCurrentThreadId());
            // Release the lock
            
            ::ReleaseSRWLockExclusive(&g_srw_lock);
            ::Sleep(10000);
        }
        
        printf("\nDownload completed successfully!\n");
        wcscpy_s(g_status, 20, L"COMPLETE");
    
        printf("gloabl status: %ws", g_status);
    
        return 42;
    }
    
    int main() {
    
        ::InitializeSRWLock(&g_srw_lock); // Initialize only once in a real application
    
        const char* url = "http://127.0.0.1:8000/a-guide-to-kernel-exploitation.pdf";
        const char* outputPath = "downloaded_file.pdf";
    
        BOOL success = FALSE;
        DWORD bytesRead = 0;
        BYTE buffer[4096];
        DWORD bytesWritten = 0;
    
            // Initialize WinINet
        g_hInternet = ::InternetOpenA("WinINet Downloader/1.0",
            INTERNET_OPEN_TYPE_PRECONFIG,
            NULL, NULL, 0);
        if (!g_hInternet) {
            printf("InternetOpenA failed: %lu\n", GetLastError());
            //goto cleanup;
        }
    
        // Open URL
        g_hUrl = ::InternetOpenUrlA(g_hInternet, url, NULL, 0,
            INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0);
        if (!g_hUrl) {
            printf("InternetOpenUrlA failed: %lu\n", GetLastError());
            //goto cleanup;
        }
    
        // Create output file
        g_fileHandle = ::CreateFile(
            L"downloaded_file.pdf",
            GENERIC_WRITE,
            FILE_SHARE_READ,
            NULL,
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            NULL
        );//https://stackoverflow.com/questions/1576187/can-createfile-open-one-file-at-the-same-time-in-two-different-thread
        if (g_fileHandle == INVALID_HANDLE_VALUE) {
            printf("CreateFileA failed: %lu\n", GetLastError());
            //goto cleanup;
            return 1;
        }
    
        printf("Downloading %s to %s...\n", url, outputPath);
    
    
    
    
        ForCreateThread* params = new ForCreateThread();
        params->handle_to_file = g_fileHandle;
        //params->url = "http://127.0.0.1:8000/a-guide-to-kernel-exploitation.pdf";
        //params->outputPath = "a-guide-to-kernel-exploitation.pdf";
        params->hUrl = g_hUrl;
        params->hInternet = g_hInternet;
    
    
        HANDLE hThread[2];
        hThread[0] = CreateThread(
            NULL,                   // Default security attributes
            0,                      // Default stack size
            (LPTHREAD_START_ROUTINE)DownloadFile, // Thread function
            (LPVOID)params,         // Pointer to the parameters structure
            0,                      // Default creation flags
            NULL                    // Don't need thread ID
        );
    
        hThread[1] = CreateThread(
            NULL,                   // Default security attributes
            0,                      // Default stack size
            (LPTHREAD_START_ROUTINE)ReadSharedData, // Thread function
            NULL,         // Pointer to the parameters structure
            0,                      // Default creation flags
            NULL                    // Don't need thread ID
        );
        
        // Wait for all three threads to finish
        WaitForMultipleObjects(
            2, // number of objects in the array
            hThread, // array of object handles
            TRUE, // bWaitAll: TRUE to wait for all objects to be signaled
            INFINITE // dwMilliseconds: INFINITE to wait indefinitely
        );
    
    
        ::CloseHandle(hThread[0]);
        ::CloseHandle(hThread[1]);
    
        return 0;
    }
    
    // Run program: Ctrl + F5 or Debug > Start Without Debugging menu
    // Debug program: F5 or Debug > Start Debugging menu
    
    // Tips for Getting Started: 
    //   1. Use the Solution Explorer window to add/manage files
    //   2. Use the Team Explorer window to connect to source control
    //   3. Use the Output window to see build output and other messages
    //   4. Use the Error List window to view errors
    //   5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
    //   6. In the future, to open this project again, go to File > Open > Project and select the .sln file
    
    

  2. PRATEEK TANEJA 0 Reputation points
    2025-08-27T20:36:27.9866667+00:00

    #include <windows.h>

    #include <stdio.h>

    SRWLOCK lock = SRWLOCK_INIT;

    int sharedData = 0;

    DWORD WINAPI ReaderThread(LPVOID) {

    AcquireSRWLockShared(&lock);
    
    printf("Reader sees value: %d\n", sharedData);
    
    ReleaseSRWLockShared(&lock);
    
    return 0;
    

    }

    DWORD WINAPI WriterThread(LPVOID) {

    AcquireSRWLockExclusive(&lock);
    
    sharedData++;
    
    printf("Writer updated value to: %d\n", sharedData);
    
    ReleaseSRWLockExclusive(&lock);
    
    return 0;
    

    }

    int main() {

    HANDLE threads[4];
    
    threads[0] = CreateThread(NULL, 0, ReaderThread, NULL, 0, NULL);
    
    threads[1] = CreateThread(NULL, 0, WriterThread, NULL, 0, NULL);
    
    threads[2] = CreateThread(NULL, 0, ReaderThread, NULL, 0, NULL);
    
    threads[3] = CreateThread(NULL, 0, WriterThread, NULL, 0, NULL);
    
    WaitForMultipleObjects(4, threads, TRUE, INFINITE);
    
    return 0;
    

    }


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.