YoonSeok OH
YoonSeok OH

Reputation: 735

Shared resource single thread writing, multiple thread reading using interlock

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.

#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;
}

Upvotes: 0

Views: 71

Answers (0)

Related Questions