0

I'm making the transition from using native Win32 API calls to manage my thread's message queue to using my own C++ code. I have encountered a question which I can't fully answer.

Given the following code snippet

LRESULT QueueConsumeThread()
{
    MSG msg = { 0 };

    HANDLE hHandles[] = { hHandle1, hHandle2 };
    while (true)
    {
        DWORD dwRes;
        switch (dwRes = ::MsgWaitForMultipleObjects(_countof(hHandles), hHandles, FALSE, INFINITE, QS_ALLEVENTS))
        {
            case WAIT_OBJECT_0 :
                DoSomething();
                break;
            case WAIT_OBJECT_0 + 1:
                DoSomething2();
                break;
            case WAIT_OBJECT_0 + _countof(hHandles):
                ATLASSERT(msg.message == WM_QUIT);
                return 1;
        }
    }

    return 1;
}

I have read in many sources that a particular thread should be a associated with a single condition_variable, also that using multiple condition_variables or invoking wait_for() or wait_until() doesn't sound too efficient.

The following source suggested implementing a safe_queue using condition_variables. I guess that PeekMessage/GetMessage/MsgWaitForMultipleObject work similarly, but what kind of data should each cell of the queue hold and be able to receive event signals?

Edit: I'm asking this as I have to write a cross-platform application.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
igal k
  • 1,883
  • 2
  • 28
  • 57
  • 1
    difficult to answer fully without knowing what kind of framework you are trying to move towards. Note that it is perfectly acceptable to call c from c++ and to handle c callbacks in c++ so the above code is actually perfectly legal. There are a few frameworks that wrap the windows api - WTL, MFC, ATL spring to mind. Or do you want something more cross-platform? – Richard Hodges Jan 30 '19 at 08:52
  • @RichardHodges, that's right, cross-platform, will edit my question – igal k Jan 30 '19 at 08:53
  • And what do the 2 event objects represent? "this queue has data"? or "this process has finished?" – Richard Hodges Jan 30 '19 at 08:55
  • 2
    There is no C++ equivalent to this OS level function – David Heffernan Jan 30 '19 at 09:08
  • @DavidHeffernan I know, that's why i asked for a similar approach, how to achieve same functionality using c++ – igal k Jan 30 '19 at 09:13
  • C++ doesn't have the concept of a message queue. So first of all you need to work out how you are going to come up with something that gives that functionality, but cross platform. What is your current plan? – David Heffernan Jan 30 '19 at 09:15
  • Current plan is to implement a SafeQueue, a condition_variable will be used to guard the push and pop operations, each element(Enum or a simple integer) would supposedly imitate event signaling, as state by HANDLE h[] = {handle1, handle2} – igal k Jan 30 '19 at 09:22
  • There is no alternative to multiple wait functions in C++. Also you cannot substitute it with multiple waits because while you are waiting for event A, event B might be signalled and unsignalled again and you never notice it. The wait-for-all capability cannot also be simulated. – Michael Chourdakis Jan 30 '19 at 11:43
  • This is why I'm asking for other approaches / methodologies. Given a thread has to for multiple messages(quit, processA,ProcessB), how should i implement it? – igal k Jan 31 '19 at 07:48
  • @igalk You can use interprocess-communication. (Refer to [this thread](https://stackoverflow.com/questions/372198/best-way-for-interprocess-communication-in-c))The quit, processA and ProcessB update objects state in shared memory and the thread monitor these state in the shared memory. – Rita Han Feb 08 '19 at 06:54

1 Answers1

1

Contrary to windows synhronization events (which can be in signalled state) std::condition_variable is decoupled from the state. So, the most natural approach would be to define several conditions and wait/report them with the single condition_variable:

std::unique_lock<std::mutex> lock(m);
cv.wait(lock, []{ return ready1 || ready2 || ready3; });
if (ready1) { ... }
if (ready2) { ... }
if (ready3) { ... }

std::unique_lock<std::mutex> lock(m);
ready1 = true;
cv.notify_one();
dewaffled
  • 2,850
  • 2
  • 17
  • 30
  • What about `QS_ALLEVENTS`? – David Heffernan Jan 30 '19 at 09:15
  • As far as I understand the goal is provide crossplatform interface for platform specific stuff. You cannot wait on HANDLE if you need without winapi anyway. So, I think, after platform specific stuff happens we need to generate a notification in standard C++ compatible way. I see nothing wrong with the single conditional variable and multiple conditions if needed here. – dewaffled Jan 30 '19 at 09:21