0

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;
}
YoonSeok OH
  • 647
  • 2
  • 7
  • 15
  • ... _why_? Using interlocked functions is a _very_ old technique in windows which has be almost totally superseded by modern standard compliant techniques. Your read/write functions can be replaced by a single line of code for the locking if you are willing to use them. – Mike Vine Dec 09 '21 at 09:48
  • and if you're not willing to use modern techniques I think you'll find it hard to get support on interlocked stuff as almost no one uses them anymore. – Mike Vine Dec 09 '21 at 09:50
  • Requests for improvements to working code go to [codereview.se]. One note is that your version allows a chain of readers to lock out a writer indefinitely. – Raymond Chen Dec 09 '21 at 12:23

0 Answers0