1

I need to solve Producer-Consumer problem in c++ using primitive synchronization objects - events, I already wrote this code

static int g_x = 0;
HANDLE hEvent1;

HANDLE aThread[2];
DWORD ThreadID;

//tread 1
void Producer()
{
    for (int i = 0; i < 100; ++i)
    {
        WaitForSingleObject(hEvent1, INFINITE);
        g_x = i;
        SetEvent(hEvent1);
    }
}
//thread 2
void Consumer()
{
    for (;;)
    {
        WaitForSingleObject(hEvent1, INFINITE);
        SetEvent(hEvent1);
    }
}

int createthreads() {
    hEvent1 = CreateEvent(NULL, FALSE, TRUE, NULL);

    // Create worker threads
    aThread[0] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)Producer, NULL,  0, &ThreadID);
    aThread[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Consumer, NULL, 0, &ThreadID);
}
int main() {
    createthreads();
}

This code doesn't work correctly: I have Infinite cycle How can I fix this code to get in console numbers from 0 to 99 ?

Rama
  • 3,222
  • 2
  • 11
  • 26
Fsdfdsg
  • 21
  • 3
  • https://msdn.microsoft.com/en-us/library/windows/desktop/ms686903(v=vs.85).aspx – Hans Passant Apr 03 '17 at 20:28
  • https://msdn.microsoft.com/en-us/library/windows/desktop/aa904937(v=vs.85).aspx – Hans Passant Apr 03 '17 at 20:29
  • for this kind of code need use 2 events – RbMm Apr 03 '17 at 20:34
  • I smell, that using 1 event for both producer thread and consumer thread will result to a suffering described by this blog https://blogs.msdn.microsoft.com/geoffda/2008/08/18/beware-of-auto-reset-events-they-dont-behave-the-way-you-think-they-do/ – daparic Nov 13 '18 at 01:06

2 Answers2

1

You need another event to syncronize this two threads. Also I set the initial state of two events to FALSE, and I send a start event to the producer thread on the main.
This way you can control when and how the process is started.

And Offtopic, createthreads must return a value.

static int g_x = 0;
HANDLE hEvent1;
HANDLE hEvent2;

HANDLE aThread[2];
DWORD ThreadID;

//tread 1
void Producer()
{
    for (int i = 0; i < 100; ++i)
    {
        WaitForSingleObject(hEvent1, INFINITE);
        g_x = i;
        SetEvent(hEvent2);
    }
}
//thread 2
void Consumer()
{
    for (;;)
    {
        WaitForSingleObject(hEvent2, INFINITE);
        SetEvent(hEvent1);
    }
}

int createthreads() {
    hEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
    hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);

    // Create worker threads
    aThread[0] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)Producer, NULL,  0, &ThreadID);
    aThread[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Consumer, NULL, 0, &ThreadID);
    return 0;
}
int main() {
    createthreads();
    SetEvent(hEvent1);
}
Rama
  • 3,222
  • 2
  • 11
  • 26
0

exist many ways implement this task, one possible - need use event pair - 2 events.

struct EventPair 
{
    HANDLE hLowEvent, hHighEvent;

    ~EventPair()
    {
        if (hHighEvent) CloseHandle(hHighEvent);
        if (hLowEvent) CloseHandle(hLowEvent);
    }

    EventPair()
    {
        hLowEvent = 0, hHighEvent = 0;
    }

    DWORD Create()
    {
        return (hLowEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) &&
            (hHighEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) ? NOERROR : GetLastError();
    }
};

struct SharedData : EventPair 
{
    int _x;
    bool _quit;

    SharedData()
    {
        _x = 0;
        _quit = false;
    }

    static DWORD WINAPI _Producer(void* This)
    {
        reinterpret_cast<SharedData*>(This)->Producer();
        ExitThread(0);
    }

    void Producer()
    {
        for (int i = 0; ; )
        {
            _x = i++;
            if (i == 100)
            {
                _quit = true;
            }
            SetEvent(hLowEvent);
            if (_quit)
            {
                return;
            }
            WaitForSingleObject(hHighEvent, INFINITE);
        }
    }

    static DWORD WINAPI _Consumer(void* This)
    {
        reinterpret_cast<SharedData*>(This)->Consumer();
        ExitThread(0);
    }

    void Consumer()
    {
        for(;;) 
        {
            WaitForSingleObject(hLowEvent, INFINITE);
            DbgPrint("%u\n", _x);
            if (_quit)
            {
                return;
            }
            SetEvent(hHighEvent);
        }
    }
};

void testPC()
{
    SharedData sd;
    if (!sd.Create())
    {
        HANDLE hThreads[2] = {};
        if (hThreads[0] = CreateThread(0, 0, SharedData::_Producer, &sd, 0, 0))
        {
            if (hThreads[1] = CreateThread(0, 0, SharedData::_Consumer, &sd, 0, 0))
            {
                WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
                CloseHandle(hThreads[1]);
            }
            else
            {
                sd._quit = true;
                SetEvent(sd.hHighEvent);
                WaitForSingleObject(hThreads[0], INFINITE);
            }
        }
        CloseHandle(hThreads[0]);
    }
}
RbMm
  • 31,280
  • 3
  • 35
  • 56