Shared resource single thread writing, multiple thread reading using interlock

77 Views Asked by At

I'm trying to implement single thread writing, multiple thread reading mechanism for shared resource management using interlock in C++, windows environment.

Q1. The result code seems to work as what I intend, but I'd like to ask for your wisdom if I am missing something.

Q2. If there is a real life or good active open source code example I can refer to, it will be really appreciated.

Following are the objectives I've taken into account.

  • Writing can only be executed by single thread and reading must be blocked when writing in order to avoid "invariant" break.
  • Reading can be executed by multiple threads.
#include <iostream>
#include <Windows.h>

char g_c = 0i8;

char g_pReadChar[3]{};

void* g_pThreads[4]{};
unsigned long g_pThreadIDs[4]{};

long long g_llLock = 0ULL;          // 0 : Not locked   /   1 : Locked (Writing)    /   2 : Locked (Reading)
long long g_llEntryCount = 0ULL;    // Thread entry count

__forceinline void Read()
{
    // <- if a thread execution is here (case 0)
    InterlockedIncrement64(&g_llEntryCount);
    // <- if a thread execution is here (case 1)

    for (unsigned long long i = 0ULL; i < 100000ULL; ++i)
    {
        if (InterlockedCompareExchange64(&g_llLock, 2LL, 0LL) == 1LL)
        {
            continue;
        }

        // <- if a thread execution is here (case 2)

        // --------------------------------------------------
        // Read data

        std::cout << g_c;

        // --------------------------------------------------

        InterlockedExchange64(&g_llLock, 1LL);  // Lock is needed in order to block case 0

        if (InterlockedDecrement64(&g_llEntryCount) == 0LL)
        {
            InterlockedExchange64(&g_llLock, 0LL);
        }
        else
        {
            InterlockedExchange64(&g_llLock, 2LL);
        }

        return;
    }

    InterlockedDecrement64(&g_llEntryCount);
}

__forceinline unsigned long __stdcall ReadLoop(void* _pParam)
{
    while (true)
    {
        Read();
        Sleep(1);
    }
}

__forceinline void Write(const unsigned long long _ullKey)
{
    for (unsigned long long i = 0ULL; i < 100000ULL; ++i)
    {
        if (InterlockedCompareExchange64(&g_llLock, 1LL, 0LL) != 0LL)
        {
            continue;
        }

        // --------------------------------------------------
        // Write data

        if (_ullKey == 0ULL)
        {
            g_c = 'A';
        }
        else if (_ullKey == 1ULL)
        {
            g_c = 'B';
        }
        else
        {
            g_c = 'C';
        }

        // --------------------------------------------------

        InterlockedExchange64(&g_llLock, 0LL);

        return;
    }
}

__forceinline unsigned long __stdcall WriteLoop(void* _pParam)
{
    unsigned long long ullCount = 0ULL;
    unsigned long long ullKey = 0ULL;
    while (true)
    {
        if (ullCount > 10000ULL)
        {
            ++ullKey;
            if (ullKey >= 3ULL)
            {
                ullKey = 0ULL;
            }
            ullCount = 0ULL;
        }

        Write(ullKey);
        ++ullCount;
    }
}

int main()
{
    g_pThreads[0] = CreateThread(nullptr, 0ULL, ReadLoop, nullptr, 0UL, &g_pThreadIDs[0]);
    g_pThreads[1] = CreateThread(nullptr, 0ULL, ReadLoop, nullptr, 0UL, &g_pThreadIDs[1]);
    g_pThreads[2] = CreateThread(nullptr, 0ULL, ReadLoop, nullptr, 0UL, &g_pThreadIDs[2]);
    g_pThreads[3] = CreateThread(nullptr, 0ULL, WriteLoop, nullptr, 0UL, &g_pThreadIDs[3]);

    Sleep(100000);

    return 0;
}
0

There are 0 best solutions below